Codeforces Round #636(div.3) A-D题解

A.Candies
  • 输入一个数字n,输出满足(k > 1) && ((2 ^ k) - 1) * x == n的任意x值,由于n < 1e9,k由2开始枚举,找到符合条件的x输出。
B.Balanced Array

输入数组长度n,问是否存在这样的一个数组:1. 数组前一半均为偶数,后一半均为奇数;2.前一半和后一半数组中元素的和相等

  • 后一半数组中为奇数,与前一半数组和相等即n/2 也是偶数
  • 若满足上面的条件,从2开始枚举 n/2 个偶数输出并求和
  • 从1开始枚举输出n/2 - 1个奇数并求和,最后输出之前偶数和与奇数和的差值
C. Alternating Subsequence

​ 做的时候读题太粗心,只看到了最大和。WA了之后读了好几次题也没看到最长这个优先级最高的条件,一直在错误的地方修改......

  • 题目中会输入一组长为n的数组,要求输出一个最长的交错子序列[1]的最大和

  • 贪心:遍历数组,每个连续的同号子串取最值。

	cin >> t;
	while(t--){
		cin >> n;
		ans = mx = 0;
		for(int i = 0; i < n; i++){
			cin >> a[i];
			if(!i || a[i] * a[i - 1] < 0){
				ans += mx;
				mx = a[i]; 
			}else{
				mx = max(mx,a[i]);
			}
		}
		cout << ans + mx << endl;
	}
D. Constant Palindrome Sum

输入由n个整数组成的数组a,和整数k,替换数组中de一些元素为[1,k]中的任一元素,使数组满足:

  1. a[i] <= k
  2. a[i] + a[n - i + 1] = x,即对称的元素和为定值( 2 <= x <= 2k)
  • 求最小替换元素的个数

对于确定的x,每对元素的交换次数确定

  1. a + b = x

  2. x ∈[min(a,b) + 1,max(a,b) + k + 1),半开半闭的区间方便合并,获得最小和,最大和,差分,此区间 + 1--起始位置 + 2,左边界(闭)-1,右边界(开) +1

  3. 其它

     交换次数存在一个最大值,当x = k + 1,为 n / 2(所有元素值的区间[1,k]);对每一对元素,计算交换次数为1的区间,使用差分思想通过cnt数组在区间外+2,区间内+1,对每一对元素的和特殊处理;在枚举完所有的元素对后,将差分数组cnt修改为前缀和即为相应x的替换次数,ans 初始化为n / 2,遍历cnt数组寻找最小替换次数。。。
    
const int kN = 2e5 + 10,kM = 4e5 + 5;
int t,n,k,l,r,ans,a[kN],cnt[kM];
//替换最少数量的元素,数组中对称元素和满足 a[i] + a[n - i + 1] = x;x为某个定值 
int main(void){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin >>t;
	while(t--){
		memset(cnt,0,sizeof(cnt));
		cin >> n >> k;
		for(int i = 1; i <= n; i++) cin >> a[i];
		for(int i = 1; i <= n / 2; i++){
			l = min(a[i],a[n - i + 1]) + 1;
			r = max(a[i],a[n - i + 1]) + k + 1;//区间左闭右开,便于合并
			cnt[1] += 2;//差分 边界[2,l) 需要两次 
			cnt[l]--;//[l,r] 一次 
			cnt[r]++;
			cnt[a[i] + a[n - i + 1]]--;//0
			cnt[a[i] + a[n - i + 1] + 1]++; 
		} 
		for(int i = 2; i <= 2 * k; i++) cnt[i] += cnt[i - 1];//计算各个x值的替换次数 
		ans = n / 2;
		for(int i = 1; i <= 2 * k; i++) ans = min(ans,cnt[i]);
		cout << ans << endl;
	}
	return 0;
}

  1. 正负交替 ↩︎

原文地址:https://www.cnblogs.com/honey-cat/p/12802986.html