传送门
感觉这题好棒啊,我就是想不到,如果没有看题解,我可能想个10年也想不出来。
就是给出n个数字,你需要进行操作,任意替换一个数字,变成([1:k]),然后使得最后满足(a[i] + a[n - i + 1])都相等。
求最小操作次数。
看了一眼以为是三分的。以为看见题目里的x,想着枚举x。
但是差分可以解决,就是对于每个(i in[1,frac{n}{2}])(a[i] + a[n - i + 1])的贡献值为0,表示可以到达,然后更改1次的区间的贡献值+1,更改2次的区间贡献值+2,注意的是三个区间不能够有并的关系就行了。然后分类讨论进行差分。最后求下前缀和,取最小值
int a[N], b[N];
int n, k;
void change(int l, int r, int pos, int c){
if(r == l) {
if(l != pos) b[l] += c, b[l + 1] -= c;
return;
}
if(l <= pos && pos <= r) {
if(pos == l) b[l + 1] += c, b[r + 1] -= c;
else if(pos == r) b[l] += c, b[r] -= c;
else {
if(r - l + 1 >= 3) {
b[l] += c, b[pos] -= c;
b[pos + 1] += c, b[r + 1] -= c;
}
}
}else b[l] += c, b[r + 1] -= c;
}
void solve(int kase){
_(n), _(k);
for(int i = 1; i <= n; i++) _(a[i]);
for(int i = 0; i <= 2 * k + 2; i++) b[i] = 0;
for(int i = 1; i <= n / 2; i++) {
int mi = min(a[i], a[n - i + 1]);
int mx = max(a[i], a[n - i + 1]);
int lone = 1 + mi, rone = mx + k;
int ltwo = 2, rtwo = 2 * k;
int now = a[i] + a[n - i + 1];
change(lone, rone, now, 1);
if(lone != 2) {
change(ltwo, lone - 1, now, 2);
}
if(rone != 2 * k) {
change(rone + 1, rtwo, now, 2);
}
}
int ans = INF, now = 0;
for(int i = 1; i <= 2 * k; i++) b[i] += b[i - 1];
for(int i = 2; i <= 2 * k; i++)
ans = min(ans, b[i]);
printf("%d
", ans);
}