首页 > 其他分享 >Codeforces Round 954(Div. 3)

Codeforces Round 954(Div. 3)

时间:2024-07-10 11:54:43浏览次数:17  
标签:idx int sum 954 len Codeforces ++ Div dp

Codeforces Round 954(Div. 3)

目录

\(C\). UpdateQueries

  • 对索引数组 \(ind\) 去重排序

  • 对字符串 \(c\) 排序

顺序遍历索引数组,将 \(s[ind[i]]\) 替换成 \(c[i]\)

void solve() {
	int n, m; cin >> n >> m;
	string s; cin >> s;
	vector<int> idx(m);
	string cset;
	for(int i = 0; i < m; i++) cin >> idx[i];
	cin >> cset;
	
	sort(idx.begin(), idx.end());
    idx.erase(unique(idx.begin(), idx.end()), idx.end());
    
	sort(cset.begin(), cset.end());
	
	int len = idx.size();
	for(int i = 0; i < len; i++){
		s[idx[i] - 1] = cset[i];
	}
	cout << s << endl;
}

\(D\). Mathematical Problem

本题思路来源于xrenena

贪心一手

当 \(n = 2\) 时,直接将这个二位数转化成数字输出即可

当 \(n > 2\) 且数字中存在 \(0\) 时 ,直接输出 \(0\) (除了 \(n = 3\) 的情况)

  • 这是因为可以直接乘 \(0\)

  • 当 \(n == 3\) 时,要特判一手,如果字符串两侧出现了 \(0\) 则直接输出 \(0\) 后 return 即可,如果两侧没有出现 \(0\) (中间出现 \(0\) 不用管),则直接交给下面的逻辑判断即可(例如 "091"、"910"

当 \(n>2\) 且无法直接乘 \(0\) 时:

  • 因为只能插入 \(n - 2\)个符号,所以必然会出现一个二位数,我们枚举这个二位数出现的位置
  • 将划分好的每个数字插入一个数组,遍历划分好的该数组
  • 遇到 \(v[i] = 1\) 时直接跳过,其他的全加起来
  • 最后判断,如果 \(sum = 0\),直接输出 \(1\)(因为这种情况可能是全是 \(1\) ,例如"101"被划分成 101
  • 如果 \(sum > 0\),直接输出 \(sum\) 即可
//如果数字中 n > 2 且 数字中存在0,直接输出0,对0乘法
//(但是要特别判断n = 3的情况,例如901,但是3位数中两边为0的时候也可以直接输出0)

//枚举每个2位数的位置,用一个v数组把分好的数字存起来
//遍历v数组,遇到1就跳过它,因为1用来做乘法的

void solve() {
	int n; cin >> n;
	string s; cin >> s;
	if(s.find('0') != -1 && n > 2){
		if(n == 3){//特判3位数中出现0在两侧的情况(091,910的情况)
			if(s[0] == '0' || s[2] == '0'){
				cout << 0 << endl;
				return;
			}
		}else{
			cout << 0 << endl;
			return;
		}
	}
	if(n == 2){
		cout << (s[0] - '0') * 10 + (s[1] - '0') << endl;
		return;
	}
	int res = 0x3f3f3f3f;
	//枚举二位数在哪个位置
	for(int idx = 0; idx < s.size() - 1; idx++){
		//v存放分好的数字
		vector<int> v;
		for(int i = 0; i < s.size(); i++){
			if(i == idx){//到了二位数的位置,直接将二位数放进v
				v.push_back((s[i] - '0') * 10 + (s[i + 1] - '0'));
				i++;
				continue;
			}
			v.push_back(s[i] - '0');
		}
		int sum = 0;
		//遍历加起来
		for(auto i : v){
			if(i == 1) continue;
			sum += i;
		}
		if(sum == 0) {//如果sum是0可以直接输出1,因为所有1都被跳过了
			res = min(1, res);
		}
		else res = min(sum, res);
	}
	cout << res << endl;
	
}

\(E\). Beautiful Array

方法一:贪心+滑动窗口

先判断是否能使数组美观:

  • 通过一个\(map\) 记录取模 \(k\) 的结果相同的数的个数(例如 \(3 \% 2\) 和 \(5 \% 2\) 的结果相同)
  • 遍历 \(map\),记录余数相同的组中,元素个数为奇数的组有多少个
  • 如果个数为奇数的组 > 1,则无论如何都无法转化为美丽数组,则输出 \(-1\),直接return

否则可以转化成美丽数组:

  • 按照余数排序一下

  • 滑动窗口维护每个余数相同的组,用一个 \(v\) 数组将组内元素全装进去排个序(这样就能保证最优选择一定是相邻两个数字进行匹配)

  • 利用 \(sum\) 求两两配对的的前缀和,

    • 如下 \(s[1]\) 表示 \((v[1] - v[0]) / k\)
    • \(s[3]\) 表示 \((v[3] - v[2])\ /\ k + s[3 - 2]\)
    • \(s[2]\) 表示 \((v[2] - v[1]) / k\)

\[v:\ 1\ 4\ 10\ 22\ 25\\ s:\ 0\ 1\ 2\ 5\ 3 \]

  • 这样我们枚举不用的点,用前缀和求代价,取最小值即可
#define int long long

//自定义排序
bool compare(int x, int y, int k) {
    return (x % k) < (y % k);
}

void solve() {
	long n, k; cin >> n >> k;
	map<int, int> hash;
	vector<int> a(n);
	for(int i = 0; i < n; i++) {
		cin >> a[i];
		hash[a[i] % k]++;
	}
	int num = 0, cnt = 0;
	//算一算余数相同的组中,元素个数为奇数的组有多少个
	for(auto [k, v] : hash){
		if(v % 2) cnt++, num = k;
	}
	//如果元素个数为奇数的组大于1个,则无论如何都不能变成完美数组
	if(cnt > 1){
		cout << -1 << endl;
		return;
	}
	//按照余数排序
	sort(a.begin(), a.end(), [&](int x, int y){
		return compare(x, y, k);
	});
	int res = 0;
	//滑动窗口维护每个余数相同的组
	int i = 0, j = 1;
	while(j < n){
		//将余数相同的数全放进v数组
		vector<int> v;
		v.push_back(a[i]);
		while(j < n && a[i] % k == a[j] % k){
			v.push_back(a[j]);
			j++;
		}
		//对v中排序
		sort(v.begin(), v.end());
		//算出每隔位的前缀和
		int len = v.size();
		vector<int> sum(len);
		for(int u = 1; u < len; u++){
			if(u - 2 >= 0) sum[u] = sum[u - 2];
			sum[u] += (v[u] - v[u - 1]) / k;
		}
		//如果v中的个数为偶数,直接前后两两配对即可
		if(len % 2 == 0) res += sum[len - 1];
		else {//如果是奇数则枚举哪个点用不上
			int ans = 0x3f3f3f3f;//记录最小代价
			for(int u = 0; u < len; u += 2){
				int all = 0;
				if(u > 0) all += sum[u - 1];
				if(u < len - 1) all += sum[len - 1] - sum[u];
				ans = min(ans, all);
			}
			res += ans;
		}
		i = j;
		j++;
	}
	cout << res << endl;
}

方法二:DP

该方法来源于yuzhongrun
详细方法题解可跳转至div3E. Beautiful Array

// https://codeforces.com/contest/1986/problem/E
#include <bits/stdc++.h>
#define caseT \
    int T;    \
    cin >> T; \
    while (T--)
using namespace std;
using ll = long long;
void solve() {
    ll n, k, ans = 0, num2 = 0;
    cin >> n >> k;
    vector<ll> nums(n);
    for (int i = 0; i < n; i++) cin >> nums[i];
    sort(nums.begin(), nums.end());
    map<ll, vector<ll>> H;
    for (ll num : nums) H[num % k].push_back(num);
    for (auto &[key, p] : H) {
        if (p.size() & 1 && ++num2 >= 2) {
            cout << "-1" << endl;
            return;
        }
        int len = p.size();
        vector<vector<ll>> dp(len, vector<ll>(2));
        dp[0][0] = INT_MAX;
        if (len > 1) dp[1] = {(p[1] - p[0]) / k, INT_MAX};
        for (int i = 2; i < len; i++) {
            ll t = (p[i] - p[i - 1]) / k;
            if (i & 1) {
                dp[i][0] = min(dp[i - 2][0], dp[i - 1][1]) + t;
            } else {
                dp[i][1] = dp[i - 1][0];
                dp[i][0] = min(dp[i - 2][0], dp[i - 2][1]) + t;
            }
        }
        ans += (len & 1) ? min(dp[len - 1][1], dp[len - 1][0]) : dp[len - 1][0];
    }
    cout << ans << endl;
}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    caseT solve();
    return 0;
}

标签:idx,int,sum,954,len,Codeforces,++,Div,dp
From: https://www.cnblogs.com/xiwen-ydys/p/18293747

相关文章

  • Codeforces Round 916 (Div. 3)
    A.ProblemsolvingLog签到题,对于给出的字符串,记录每个字母出现的次数,然后遍历一遍,如果对应的字母出现的次数大于它的位次,则说明该题被解出来了,最后输出解题数量即可点击查看代码#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<vector>#......
  • Codeforces Round 956 (Div. 2) 部分题解A~C
    A.ArrayDivisibility题目大意构造长度为n的数组,满足:所有j的aj之和可以被k整除,其中j是k的倍数,k的取值为1~n。思路构造序列1->n即可满足条件。代码实现voidsolve(){  lln;cin>>n;  for(inti=1;i<=n;i++)cout<<i<<"";  cout<<"\n"......
  • joi2022_yo2_c 国土分割 (Land Division) 题解
    国土分割(LandDivision)推销我的洛谷博客。题意给定一个\(n\timesm\)的矩阵\(a\),你需要选择在横向或纵向分割至少一次,使得每个分割出来的小矩阵的\(a_{i,j}\)之和相等。数据范围\(1\leqslantn,m\leqslant50\)。\(1\leqslanta_{i,j}\leqslant10^5\)。思......
  • Codeforces Round #956 (Div. 2) and ByteRace 2024
    Preface连着好几天因为熬夜看LOL比赛导致白天精神萎靡,都没精力VP了而且明天就要开始统一训练了,趁着最后一天补一下前两天因为看比赛没打的这场吧这场只能说是战术正确,想了会E没啥思路就马上转头去把F写了,后面回头慢慢想E也想出来了,最后极限2h14min出了EA.ArrayDivisibility......
  • codeforces 955 div 2 D
    题目链接D.Beautyofthemountains题目大意解题思路首先记录所有雪山和没有雪山两种山峰的高度差为\(tot\),然后对于每个可能的子矩,我们可以每次给所有山峰都加一或者减一,因此只要计算出矩阵内两种山峰的个数差的绝对值我们就能得到每次操作该子矩阵对tot的贡献\(z_{i}......
  • Codeforces Round956(div2) A~C
    A.ArrayDivisibility题意:对于所有k=1~n,能被j=1~n整除,要求以这些j作为下标a[j]的和也能够被k整除思路:题目有点绕,但是仔细读懂题目其实会发现,其实就是从1到n按顺序输出一遍...,别被样例忽悠了voidsolve(){ intn; cin>>n; for(inti=1;i<=n;i++){ cout......
  • Codeforces Round 953(Div.2) 题解(A-E)
    CodeforcesRound953(Div.2)题解(A-E)A题意Alice有n本书,第一本书有\(a_1\)页,序号为1,第二本书有\(a_2\)页,序号为2,……,第n本书有\(a_n\)页,序号为n。Alice将把所有书分成两堆,并阅读每一堆中序号最大的一本书。Alice喜欢读书,请你告诉她,她最多可以读多少页的书。Solution第......
  • CodeForces CF1980C Sofia and the Lost Operations 题解 但是最后TLE 仅供思路参考
    CodeForcesCF1980CSofiaandtheLostOperations题解嗨嗨,又来了啊,蒟蒻再来一篇题解SofiaandtheLostOperations题面翻译索菲亚有一个包含$n$个整数的数组$a[1],a[2],…,a[n]$。有一天她对这个数组感到厌倦,于是决定顺序地对其应用$m$个修改操作。每个修改操作由一......
  • Codeforces Round #956 (Div. 2) C. Have Your Cake and Eat It Too
    CodeforcesRound#956(Div.2)C.HaveYourCakeandEatItToo题目大意:有长度为nnn的数组a......
  • / 用上指针 ,定义函数实现:终端输入 add + sub - mul * div / 执行 两个数 的加减乘除
    #include<stdio.h>#include<string.h>intmy_add(intdata1,intdata2){  returndata1+data2;}intmy_sub(intdata1,intdata2){  returndata1-data2;}intmy_mul(intdata1,intdata2){  returndata1*data2;}intmy_di......