题意,一个数组 a a a,包含 n n n个整数,所有 a a a i _i i都不超过一个整数 k k k,你可以做一些替换数组中元素的操作:将 a a a i _i i替换为 [ 1 ; k ] [1;k] [1;k]范围中的数,最终使得整个数组满足如下条件:
- 在替换完成后,所有的 a a a i _i i是正整数且不超过 k k k;
- 对 i i i从 1 1 1~ n 2 \frac{n}{2} 2n满足条件: a a a i _i i+ a a a n − i + 1 _{n-i+1} n−i+1= x x x,对所有的 n 2 \frac{n}{2} 2n来说, x x x都相同。
需要求的是最少的替换次数使数组满足条件。
用例:
input:
4 3
1 2 2 1
output:
1
// 解释:将a[0]替换为3,即可满足条件
题解:
首先要分析三种情况:假设已知
x
x
x可以使得替换次数最少。那么:
- a a a i _i i+ a a a n − i − 1 _{n-i-1} n−i−1=x, 不用替换
- m i n ( min( min( a a a, a a a n − i − 1 _{n-i-1} n−i−1 ) ) )+ 1 1 1 < = x <=x <=x && m a x ( max( max( a a a, a a a n − i − 1 _{n-i-1} n−i−1 ) ) )+ k k k > = x >= x >=x ,那么只需要替换一个元素就可以使得二者的和等于 x x x,那么这也就是一个区间 [ m i n ( a , a [min(a,a [min(a,a n − i − 1 _{n-i-1} n−i−1 ) + 1 , m a x ( a , a )+1,max(a,a )+1,max(a,a n − i − 1 _{n-i-1} n−i−1 ) + k ] )+k] )+k],只要 x x x的值在这个区间内,那么就只用替换一个元素。
- 上述两个条件都不满足,那么必须得同时替换 a a a i _i i和 a a a n − i − 1 _{n-i-1} n−i−1才能使得等于 x x x,也就是得替换两个。
所以,如果把左区间的端点
l
l
l设为+
1
1
1,右区间的端点
r
+
1
r+1
r+1设为-
1
1
1,那么再对所有端点的值求一个前缀和
p
r
e
pre
pre,就可以得到
p
r
e
pre
pre
x
_x
x有多少对组合满足只替换一个就可以满足和为
x
x
x的条件,同时需要减去
c
n
t
cnt
cnt
x
_x
x的值,
c
n
t
cnt
cnt
x
_x
x是和为
x
x
x的已有的个数,所以最少替换一个的值就是
p
r
e
pre
pre
x
_x
x-
c
n
t
cnt
cnt
x
_x
x。
那么还有得替换两个的怎么求?因为
p
r
e
pre
pre
x
_x
x为替换一个能满足条件的个数,并且不用替换的也被包含在了其中,所以得替换两个的个数就是
(
(
(
n
2
\frac{n}{2}
2n-
p
r
e
pre
pre
x
_x
x
)
)
)
∗
2
*2
∗2。
对每一个可能的 x x x进行遍历,求出其最小的 p r e pre pre x _x x- c n t cnt cnt x _x x+ ( ( ( n 2 \frac{n}{2} 2n- p r e pre pre x _x x ) ) ) ∗ 2 *2 ∗2。
#include <bits/stdc++.h>
using namespace std;
int main() {
int t;
cin >> t;
while (t--) {
int n, k;
cin >> n >> k;
vector<int> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
vector<int> cnt(2*k+1), pre(2*k+1);
for (int i = 0; i < n/2; i++) {
cnt[a[i] + a[n-i-1]]++;
}
for (int i = 0; i < n/2; i++) {
int Min = min(a[i], a[n-i-1]) + 1;
int Max = max(a[i], a[n-i-1]) + k;
pre[Min]++;
pre[Max+1]--;
}
for (int i = 1; i <= 2*k; i++) {
pre[i] = pre[i-1] + pre[i];
}
int res = n;
for (int i = 1; i <= 2*k; i++) {
res = min(res, (pre[i] - cnt[i]) + (n/2 - pre[i])*2);
}
cout << res << endl;
}
}