Codeforces Round #636 D. Constant Palindrome Sum(差分/好题)
You are given an array aa consisting of nn integers (it is guaranteed that nn is even, i.e. divisible by 22 ). All aiai does not exceed some integer kk .
Your task is to replace the minimum number of elements (replacement is the following operation: choose some index ii from 11 to nn and replace aiai with some integer in range [1;k][1;k] ) to satisfy the following conditions:
- after all replacements, all aiai are positive integers not greater than kk ;
- for all ii from 11 to n2n2 the following equation is true: ai+an−i+1=xai+an−i+1=x , where xx should be the same for all n2n2 pairs of elements.
You have to answer tt independent test cases.
The first line of the input contains one integer tt (1≤t≤1041≤t≤104 ) — the number of test cases. Then tt test cases follow.
The first line of the test case contains two integers nn and kk (2≤n≤2⋅105,1≤k≤2⋅1052≤n≤2⋅105,1≤k≤2⋅105 ) — the length of aa and the maximum possible value of some aiai correspondingly. It is guratanteed that nn is even (i.e. divisible by 22 ). The second line of the test case contains nn integers a1,a2,…,ana1,a2,…,an (1≤ai≤k1≤ai≤k ), where aiai is the ii -th element of aa .
It is guaranteed that the sum of nn (as well as the sum of kk ) over all test cases does not exceed 2⋅1052⋅105 (∑n≤2⋅105∑n≤2⋅105 , ∑k≤2⋅105∑k≤2⋅105 ).
For each test case, print the answer — the minimum number of elements you have to replace in aa to satisfy the conditions from the problem statement.
4 4 2 1 2 1 2 4 3 1 2 2 1 8 7 6 1 1 7 6 3 4 6 6 6 5 2 6 1 3 4
0 1 4 2
题意大概是给一个长度为偶数的序列(每个数不超过k),问最少更改多少次元素能使每个数对的和一样。
注意到一个数对的和要变为S的改变次数一共有三种情况:
1.a+b=S,代价为0.
2.当S-(a+b)>0时S-(a+b)<=k-min(a,b);当S-(a+b)<0时(a+b)-S<max(a,b)(注意这里不能取等号,因为每个数的值必须大于等于1);同时S!=a+b.代价为1.
3.其他情况。代价为2.
因此开一个差分数组s,枚举每一个数对,根据这个数对把其对应的代价为2的S的值的区间整体加上2(利用差分常规操作),代价为1的区间整体加上1,代价为0的区间空出来。最后求一边差分数组前缀和,就能得到每个S的代价了,从中取最小即可。注意,可以预先swap(a,b)使a是较小数b是较大数,这样就能对区间进行化简,利于差分。
#include <bits/stdc++.h> using namespace std; int n,k,a[200005]; long long s[400005]; int main() { int t; cin>>t; while(t--) { cin>>n>>k; int i; memset(s,0,sizeof(s)); for(i=1;i<=n;i++)scanf("%d",&a[i]); for(i=1;i<=n/2;i++) { int x=a[i],y=a[n-i+1]; if(x>y)swap(x,y); s[0]+=2,s[x+1]-=2; s[x+1]+=1,s[x+y]-=1;//空出s=x+y 因为此种情况花费为0 s[x+y+1]+=1,s[k+y+1]-=1; s[k+y+1]+=2,s[2*k+1]-=2; } long long ans=0x3f3f3f3f; for(i=0;i<=2*k;i++) { if(i!=0)s[i]+=s[i-1]; ans=min(ans,s[i]); } cout<<ans<<endl; } return 0; }