Codeforces Round #636 (Div. 3) D Constant Palindrome Sum【1343D】 (前缀和)

Constant Palindrome Sum

题意

给定一个长度为 n n n(保证 n n n是偶数)的数字序列 a n a_n an和一个 k k k,可以对序列进行若干次操作,每次操作可以将其中一个 a i a_i ai替换成 [ 1 , k ] [1,k] [1,k]中的任意一个数,要求经过若干次操作后对于每个 i i i, i ≤ n 2 i\leq\frac{n}{2} i2n, 都满足 a i + a n − 1 + i = s u m a_{i}+a_{n-1+i}=sum ai+an1+i=sum,要求最少的操作次数。

思路

很明显, s u m sum sum的最终取值只能是 [ 2 , 2 ∗ k ] [2,2*k] [2,2k]
我们可以枚举 s u m sum sum,对每一个 s u m sum sum计算最少操作次数,然后对所有的最少操作次数取最小值,就可得到最终答案。
具体来说,要满足条件,对于每一对 ( a i , a n − 1 + i ) (a_{i},a_{n-1+i}) (ai,an1+i),我们有三种操作:

  1. 这一对之和已经等于 s u m sum sum,不需要操作。使用 c n t [ a [ i ] + a [ n − 1 + i ] ] cnt[a[i]+a[n-1+i]] cnt[a[i]+a[n1+i]]记录这个和出现的次数。
  2. 这一对之和不等于 s u m sum sum,可以只经过一次操作到之和等于 x x x。对于每一对来说,它们经过一次操作所得的两个数之和是有上下限的。我们可以记录这个上下限出现的次数,利用前缀和来统计有几对只经过一次操作就可满足条件。设下限为 x x x,上限为 y y y,然后令 p r e f [ x ] + + , p r e f [ y + 1 ] − − pref[x]++,pref[y+1]-- pref[x]++,pref[y+1],再对 p r e f pref pref求前缀和。这样, p r e f [ s u m ] pref[sum] pref[sum]便表示只经过一次操作就能满足条件的数对的个数,这些数对中也包括哪些不需要操作的数对,所以最终必须经过一次操作的数对个数为 p r e f [ s u m ] − c n t [ s u m ] pref[sum]-cnt[sum] pref[sum]cnt[sum]
  3. 这一对之和不等于 x x x,必须经过两次操作到之和等于 x x x。由2知,总数对个数 n 2 \frac{n}{2} 2n减去 p r e f [ s u m ] pref[sum] pref[sum]就是需要经过两次操作才能满足条件的数对个数。

代码

#include<bits/stdc++.h>

using namespace std;

int t;
int n,k;
int a[200005];

int main()
{
    cin >> t;
    while(t--){
        cin >> n >> k;
        vector<int> cnt(2*k+1);
        vector<int> pref(2*k+2);
        for(int i = 1; i <= n; ++i)
            cin >> a[i];
        for(int i = 1; i <= n/2; ++i){
            ++cnt[a[i]+a[n-i+1]];
            int x = min(a[i],a[n-i+1])+1;//下限
            int y = max(a[i],a[n-i+1])+k;//上限
            ++pref[x];
            --pref[y+1];
        }
        for(int i = 1; i <= 2*k+1; ++i)
            pref[i] += pref[i-1];
        int ans = 1e9;
        for(int sum = 2; sum <= 2*k; ++sum)//枚举sum
            ans = min(ans,(pref[sum]-cnt[sum])+(n/2-pref[sum])*2);
        printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值