[ACM]【prefix】codeforces Round #636 (Div.3) Constant Palindrome Sum

Constant Palindrome Sum

题意:给一串数,做最少次的改动(可将其变为1至K的任意数),使其第i个元素与第n-i+1个元素的值的和为一确定数。

在这里插入图片描述

思路:

参考了题解。
前缀和+暴力。
果然cf div3就是死揪着前缀和不放了
遍历每一个可能的和x,找出改动次数最小的。
对于每一对,改动分三种,不改,改一个,两个都改。
改一个的话,这一对的和的范围是:
min(a[i],a[n-i+1])+1至max(a[i],a[n-i+1])+k
(即把大的那个替换成1和把小的那个替换成k)
怎么知道有多少对的和的改变范围包括x呢?
这里就用到了前缀和。lower bound处+1,upper bound处-1,计算前缀和,(注意因为是闭区间,所以upper bound处还要在加上1)那么得到的pref[x]就意味着,可以通过不改变或者只改变其中一个数而达到和等于x的数对的对数。
答案于是就是(pref[x]-cnt[x]+2×(n/2-pref[x]))了。
感觉这个操作在哪见过,总之学到惹

#include<bits/stdc++.h>
using namespace std;
const int inf=1e9;
#define forn(x,y,z) for(int x=(int)y;x<=(int)z;x++)
int main(){
	int t,n,k;
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&k);
		vector<int>a(n+1);
		forn(i,1,n) cin>>a[i];
		vector<int>cnt(2*k+2);
		forn(i,1,n/2) cnt[a[i]+a[n-i+1]]++;
		vector<int>pref(2*k+4);
		forn(i,1,n/2){
			pref[min(a[i],a[n-i+1])+1]++;
			pref[max(a[i],a[n-i+1])+k+1]--;
		}
		//变成前缀和 
		forn(i,1,2*k+4) pref[i]=pref[i-1]+pref[i];
		int ans=inf;
		forn(i,2,2*k) ans=min(ans,pref[i]-cnt[i]+(n/2-pref[i])*2);
		printf("%d\n",ans);
	}
}
发布了20 篇原创文章 · 获赞 1 · 访问量 577

猜你喜欢

转载自blog.csdn.net/weixin_45497996/article/details/105732105
今日推荐