这套div3还可以,比较简单吧,D题感觉比较不错,这里补一下D题
D题解题思路:
- D题原本还想用二分三分去做,但是感觉不太靠谱,hhh
- 差分的思想,其实还好
- 首先我们这里需要列出几种情况,他们的和为x + y
x = a i x = a_i x=ai y = a n − i + 1 y = a_{n - i + 1} y=an−i+1
- 首先是保持不变,那么他们的和仍然为x + y, 操作的数目是0
- 增大其中一个数,如果我们想操作一次让他最大,那么我们需要操作x,y中较小的那个数,所以我们可以操作一次达到的最大范围是max(x,y) + k 我们让那个小的数直接变为k
- 我们还可以操作一次让这个数值变为最小,那么就是min(x,y) + 1 就是让那个比较大的值变为 1
- 剩下的是操作两次得出的数值,首先我们想让他们变为最小,那么肯定是2,让2个都改变,那么2 ~ min(x,y) + 1 - 1这之间都是改变2次,min(x,y) + 1 ~ max(x,y) + k 中除了x +y 改变0次之外,剩下的都是改变1次,那么 max(x,y) + k + 1 ~ 2 * k 之间都是改变2次。
- 因此我们根据上述的分类,我们利用差分的原理进行计算
- 首先是ans[2] += 2 因为值2 ~ min(x,y) + 1 - 1都需要操作2次
- 然后 ans[min(x,y) + 1] – ,因为之后到 ans[max(x,y) + k] 都是操作一次即可
- 其中ans[x+y] --, 因为x+y 这里不需要改变
- 然后还是要对ans[x + y + 1]++,因为只有x+y的位置是不需要操作的
- 最后对ans[max(x,y) + k + 1]++,因为之后都需要操作2次才可以变换
- 然后对这个差分数组求前缀和,然后找最小值就行,最小值就是数组中操作的最小次数
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 400010;
int a[N];
int ans[N];
int main(){
int t;
scanf("%d",&t);
while(t--){
int n,k;
scanf("%d%d",&n,&k);
for (int i = 1; i <= n; i++){
scanf("%d",&a[i]);
}
memset(ans,0,sizeof ans);
for (int i = 1; i<= n/ 2; i++){
int x = a[i], y = a[n - i + 1];
ans[2] += 2;
ans[x + y] --;
ans[min(x,y) + 1] --;
ans[max(x,y) + 1 + k] ++;
ans[x + y + 1] ++;
}
for (int i = 2; i <= 2*k; i++){
ans[i] += ans[i - 1];
}
int mi = 1e9;
for (int i = 2;i <= 2 *k ; i++){
mi = min(mi,ans[i]);
}
printf("%d\n",mi);
}
return 0;
}