Codeforces 636(Div. 3)D. Constant Palindrome Sum(差分数组)

无

昨晚div.3的D题,1个多小时,一点头绪没有,今天晚上补题的时候才发现我tm题意读错了!!!啊啊啊啊啊!!!!!
我就说嘛!
那个区间 [ 1 ; k ] 是1到k的所有数字,而不是数组[1,k]中的数,我以为是后者,一直在想确定x后两个数加起来还要判断能不能等于x,因为数组[1,k]中的数可是不确定的
今天才反应过来题意读错了!(虽然要是没读错题也不一定能做出来,但总比读错了题一点思路没有强呀!)

枚举x,x的范围是[2,2*k]
定义一个数组vis
vis[i]表示当x=i时有多少对(a[j],a[n-j+1])和为x
这个循环一遍即可求出

定义数组cis和数组p
对于一对数(a[i],a[n-i+1]),首先a[i]+a[n-i-1]不需要修改任何数
而区间 [ min(a[i],a[n-i+1])+1 , max(a[i],a[n-i+1])+k]中的数都可以用这一对数只修改一个数的前提下得到,p数组是cis数组的差分数组
因此cis[i]表示当x=i是有多少对(a[j],a[n-j+1])只修改一个数即可得到x

对于差分数组,当我们要计算区间修改时,可利用差分数组
比如数组a={1,2,3,4,5,6,7,8,9}
则差分数组p[i]=a[i]-a[i-1]
然后假设给数组a的区间[l,r]中加上值k
可进行如下操作
p[l] + = k;
p[r+1] - = k
最后在通过差分数组算出原数组即可
即a[i]=p[i]+a[i-1]
可见,当需要多次修改,单次查询时,差分数组似乎比线段树要好写一点。。。。

最后跑一遍x的取值取最小值即可

代码:

#include <bits/stdc++.h>
#define ll long long
using namespace std;

int l=9999999,r=-1;
int a[200005];
int vis[400005];
int cis[400005];
int p[400005];
int main()
{
    int t,n,k;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d",&n,&k);
        for(int i=1;i<=n;i++)
        {scanf("%d",&a[i]);}
        for(int i=1;i<=2*k+1;i++)
        {vis[i]=0;cis[i]=0;p[i]=0;}
        for(int i=1;i<=n/2;i++)
        {
            int x=a[i]+a[n-i+1];
            int l=min(a[i],a[n-i+1])+1;
            int r=max(a[i],a[n-i+1])+k;
            vis[x]++;
            p[l]+=1;p[r+1]-=1;
            p[x]+=(-1);p[x+1]-=(-1);
        }
        for(int i=2;i<=2*k;i++)
        {cis[i]=p[i]+cis[i-1];}
        int minn=99999999;
        for(int i=2;i<=2*k;i++)
        {
            int ans=n;
            ans-=2*vis[i];
            ans-=cis[i];
            minn=min(ans,minn);
        }
        printf("%d\n",minn);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值