[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);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章