#636 (Div. 3)D.Constant Palindrome Sum(差分)

题目描述

You are given an array a consisting of n integers (it is guaranteed that n is even, i.e. divisible by 2). All ai does not exceed some integer k.
Your task is to replace the minimum number of elements (replacement is the following operation: choose some index i from 1 to n and replace ai with some integer in range [1;k]) to satisfy the following conditions:
after all replacements, all ai are positive integers not greater than k;
for all i from 1 to n2 the following equation is true: ai+an−i+1=x, where x should be the same for all n2 pairs of elements.
You have to answer t independent test cases.

Input

The first line of the input contains one integer t (1≤t≤104) — the number of test cases. Then t test cases follow.
The first line of the test case contains two integers n and k (2≤n≤2⋅105,1≤k≤2⋅105) — the length of a and the maximum possible value of some ai correspondingly. It is guratanteed that n is even (i.e. divisible by 2). The second line of the test case contains n integers a1,a2,…,an (1≤ai≤k), where ai is the i-th element of a.
It is guaranteed that the sum of n (as well as the sum of k) over all test cases does not exceed 2⋅105 (∑n≤2⋅105, ∑k≤2⋅105).

Output

For each test case, print the answer — the minimum number of elements you have to replace in a to satisfy the conditions from the problem statement.

Example

input
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
output
0
1
4
2

题目大意

给你一个偶数元素个数的数组,这个数组里全是1~k的数,你可以改任意位置的数字,使得对于所有i<=(n/2),a[i]+a[n-i+1]=x(定值),求最小的修改次数。

这道题看了很久也没做出来。。。后来看了题解才知道要用差分(差分我已经忘干净了,第一次见差分的题)
不知道差分的看这:前缀和与差分

题目分析

这道题暴力枚的时间复杂度是O(nk),肯定会超时。
我们可以用一个差分数组d[]来维护定点x在取不同值时的修改次数这个区间。

当枚举到第i个数时:
minn //表示a[i]与a[n-i+1]的最小值
maxn //表示a[i]与a[n-i+1]的最大值
sum //表示a[i]与a[n-i+1]的和
首先,我们知道定值x的范围是[2,2 * k]
只修改一次时,sum可以达到的范围是[minn+1,maxn+k]
修改两次时,sum可以达到[2,2 * k]中的任何数

  1. 当x的取值范围在[2,minn+1)和(maxn+k,2 * k]时,sum要想达到x,就必须修改两次,所以[2,minn+1)U(maxn+k,2 * k]这个范围内d都要加上2。
  2. 当x的取值在[minn+1,maxn+k]时,sum要想到大x,只需要修改一次,所有[minn+1,maxn+k]这个范围内d只需要都加上1。
  3. 注意:当x==sum时,不需要进行修改。

把某个区间范围内的数,都加上某个数的操作就是差分,不会的可以看一下上面的链接。

代码如下
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
#include <iomanip>
#define LL long long
using namespace std;
const int N=2e5+5;
int a[N],d[2*N];
int main()
{
    int t;
	scanf("%d",&t);     //数据范围较大,推荐用scanf输入
	while(t--)
	{
		int n,k;
		scanf("%d%d",&n,&k);
		memset(d,0,sizeof d);  //将d清0
		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
		
		for(int i=1;i<=n/2;i++)
		{
			int maxn=max(a[i],a[n-i+1]);   //先求出maxn,minn,sum
			int minn=min(a[i],a[n-i+1]);
			int sum=a[i]+a[n-i+1];
			d[2]+=2;          //差分操作
			d[minn+1]--;
			d[sum]--;
			d[sum+1]++;
			d[maxn+k+1]++;
		}
		int ans=d[2];
		for(int i=3;i<=2*k;i++)
		{
			d[i]+=d[i-1];        //用前缀和操作恢复原数组
			ans=min(ans,d[i]);   //找出最小值
		}
		cout<<ans<<endl;
	}
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lwz_159

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值