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);
}
}