【题目翻译】
给你一个包含n个数字的序列a,你可以将其中某一个数字改成另外一个[1,k]之间的数字。 要求修改之后,对于所有的i∈[1..n/2],a[i]+a[n-i+1]=x,这里的x是一个定值。 n给的一定是偶数。 问你最少操作次数是多少。 一开始给的序列a中的每个数字也都是在[1..k]的范围内。【题解】
假设我们的目标已经确定了,就是x。那么对于每一对a[i],a[n-i+1]来说。 我们能够把他们的和通过一次操作变到什么程度? 应该是min(a[i],a[n-i+1])+1..max(a[i],a[n-i+1])+k这个范围内。 也就是说我们只需要看一下x这个数字被多少个区间包裹着->对应多少对可以通过一次操作得到x 不过还有不需要操作就直接能变成x的情况,这种情况也会把这个数字包裹住。 所以需要在这个基础上减去恰好为x的情况。 那么需要操作两次的对数有多少呢?当然就是n/2减去1次和0次的情况啦。 x被多少个区间包裹着,可以用左区间+1,右区间减1的方式得到。 这里枚举x要从1..2*k枚举,然后初始化不能用memset,还是得这次用了哪些数字就把哪些数字初始化(1..2*k+1!!!)。 因为$∑k<=2*10^5$所以这样初始化不会超时。【代码】
#include<bits/stdc++.h>
#define ll long long
#define rei(x) scanf("%d",&x)
#define rel(x) scanf("%I64d",&x)
#define rep1(i,a,b) for (int i = a;i <= b;i++)
#define rep2(i,a,b) for (int i = a;i >= b;i--)
using namespace std;
const int N = 2e5;
int T;
int n,k;
int a[N+10];
int cnt[N*2+10];
int l[N*2+10];
int main(){
#ifdef LOCAL_DEFINE
freopen("D:\rush.txt","r",stdin);
#endif
rei(T);
while (T--){
rei(n);rei(k);
rep1(i,1,n) rei(a[i]);
rep1(i,1,n/2){
cnt[a[i]+a[n-i+1]]++;
int mi = min(a[i],a[n-i+1]),ma = max(a[i],a[n-i+1]);
mi = mi+1;ma = ma + k;
l[mi]++;l[ma+1]--;
}
int x = 0;
int ans = -1;
rep1(i,1,2*k){
x+=l[i];
int X = i;
int tmp = x-cnt[X];
int tmp2 = n/2-x;
tmp = tmp + tmp2*2;
ans = (ans==-1?tmp:min(ans,tmp));
}
printf("%d
",ans);
rep1(i,1,2*k+1) cnt[i] = 0,l[i] = 0;
}
return 0;
}