D. Constant Palindrome Sum(差分数组维护)

D. Constant Palindrome Sum

题目

思路

  • 题意:给我们一个长度为n的数组a,n恒为偶数,之后有给了一个k并且给了他的n个元素的值,先在我们需要对这个序列做变化,使 a [ i ] + a [ n − i + 1 ] = = x , 1 < = i < = n / 2 a[i]+a[n-i+1]==x,1<=i<=n/2 a[i]+a[ni+1]==x,1<=i<=n/2,x为一个常数,问我们最少需要变化多少个数,有一个常数x使上式成立,对于每一个变换我们可以把序列中的任意一个元素 a [ i ] a[i] a[i]变为1~k之间的任意一个数,求最小需要变化的元素的数量
    注意:无论 a r [ i ] ar[i] ar[i]变化与否它的范围都是在 1   k 1~k 1 k之间

差分铺垫知识

  • 分析:
  1. 要想得到最小的变化次数,我就要找到一个合适的 x x x,使a中的元素尽可能的少改变,最好不改变,,,但是怎找到这个合适的x呢??
  2. 我们的解决分案也很简答粗暴,那就是暴力枚举所有可能的x,因为 1 = < a r [ i ] < = k    ,   1=<ar[i]<=k~~,~ 1=<ar[i]<=k  , 所以 2 < = x < = 2 k 2<=x<=2k 2<=x<=2k
  3. 我们面的情况有三种
    • 第一个种一个都不用改,那么我们直接统计 a [ i ] + a [ n − i + 1   a[i]+a[n-i+1~ a[i]+a[ni+1 的和出现的次数,这个“和”是有可能作为后选的x的
    • 第二种的情况我可以改变 a [ i ] 、 a r [ n − i + 1 ] a[i]、ar[n-i+1] a[i]ar[ni+1]这两个数中的一个数,那么改完之后 a [ i ] + a r [ n − i + x ] a[i]+ar[n-i+x] a[i]+ar[ni+x] 所能表示的范围是 [ m i n ( a [ i ] , a [ n − i + 1 ) + 1 ,   m a x ( a [ i ] , a [ n − i + 1 ] + k ] [min(a[i],a[n-i+1)+1,~max(a[i],a[n-i+1]+k] [min(a[i],a[ni+1)+1, max(a[i],a[ni+1]+k]在这个表示的区间范围内都是可以表示的数,都可以作为待选的x我们也要统计这个区件内的数当i的取值不同的的出现的次数,统计这个事情就要差分数组来维护了,怎么维护,考虑我们枚举的区间x的为 [ 2 , 2 k ] [2,2k] [2,2k],我们假设差分数组为 p r e f [ ] pref[] pref[],由于我们改变 a [ i ] 、 a r [ n − i + 1 ] a[i]、ar[n-i+1] a[i]ar[ni+1]这两个数中的一个数,那么改完之后 a [ i ] + a r [ n − i + x ] a[i]+ar[n-i+x] a[i]+ar[ni+x] 所能表示的范围是 [ m i n ( a [ i ] , a [ n − i + 1 ) + 1 ,   m a x ( a [ i ] , a [ n − i + 1 ] + k ] [min(a[i],a[n-i+1)+1,~max(a[i],a[n-i+1]+k] [min(a[i],a[ni+1)+1, max(a[i],a[ni+1]+k]在这个表示的区间范内的数进行区间+1操作,而转化为差分上的操作就是: p r e f [ m i n ( a [ i ] , a [ n − i + 1 ) + 1 ] + 1 ,       p r e f [ m a x ( a [ i ] , a [ n − i + 1 ] ) + k ] − 1 pref[min(a[i],a[n-i+1)+1]+1,~~~~~pref[max(a[i],a[n-i+1])+k]-1 pref[min(a[i],a[ni+1)+1]+1,     pref[max(a[i],a[ni+1])+k]1
    • 第三种情况是改变两个数,改变两个数那么 a [ i ] + a [ n − i + 1 ] a[i]+a[n-i+1] a[i]+a[ni+1]可以表示 [ 2 , 2 k ] [2,2k] [2,2k]之间的任何数,所以留到最后在考虑就行了
  4. 考虑完这三种情况之后就是一一枚举可能的x了

代码


#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
void fre() { freopen("A.txt","r",stdin); freopen("Ans.txt","w",stdout); }
#define INF 0x3f3f3f3f

int main()
{
    /* fre(); */
    int t; 
    scanf("%d", &t);
    while(t --)
    {
        int n, k;
        scanf("%d %d", &n, &k);
        vector<int> ar(n + 1);
        for(int i = 1; i <= n; i ++)
            scanf("%d", &ar[i]);
        vector<int> cnt(2 * k + 1);
        //第一种一个都不需要更改
        for(int i = 1; i <= n/2; i ++)
            cnt[ar[i] + ar[n - i + 1]] ++;
        //第二种只需要改一个
        vector<int> pref(2*k + 2);
        for(int i = 1; i <= n/2; i ++)
        {
            int l = min(ar[i], ar[n - i + 1]) + 1;      //[l, r] 更改ar[i] 或者ar[n - i + 1] 其中一个数所能得到的最多范围
            int r = max(ar[i], ar[n - i + 1]) + k;
            //先用差分维护需要加值的区间 
            pref[l] ++;
            pref[r + 1] --;
        }
        //差分前缀和,用来表示区间中的增加值之后的数
        for(int i = 1; i <= 2*k; i ++)
            pref[i] += pref[i - 1];
        //对剩下的第三种情况,结合前两种进行考虑
        int ans = INF;
        for(int i = 2; i <= 2*k; i ++)
            ans = min(ans, (pref[i] - cnt[i]) + 2*(n/2 - pref[i]));
        printf("%d\n", ans);
    }

    return 0;
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值