CodeForces - 808D(STL+思维)

题目链接:CodeForces - 808D


题意:给一个长度为n的正整数序列,要求最多移动移动数使得数列可以分为相等的两个部分(前面的和与后面的和

      相等),注意不是交换两个数,而是移动一个数,其它数的相对顺序保持不变。


题解:因为要求前面的和与后面的和,那么用前缀和数组记录前缀和,用的时候作一个减法就能很快的求出两部分的

      和。要满足题目要求,没移动前的数组前后两部分必须满足以下条件:

      1.(sum-sum) % 2 == 0   或  (sum-sum) % 2 == 0; 两部分要么相等要么差一个数,想等的话

        相减为零,需要移动一个数的话相减就是这个数的两倍。

      2.相差的这个数在大的那个部分里存在。

      第一个条件用前缀和数组可以很快解决,后面这个条件用一个map做映射也可以很快解决。先将所有数存入M

      中,然后在枚举前后部分和时从前往后遍历数组每遇到一个数就将这个数加入M,同时在M后中将这个数去。

      这样就可以很快的知道前后两部分有没有需要的数了。这是因为它们的顺序是不变的,排在前面的就是前面部

      分,后面的就是后面的。


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

const int maxn = 1e5 + 10;
long long n, a[maxn];
long long sum[maxn], s1, s2;
map<long long, long long> m1;       //用来记录前面部分的数
map<long long, long long> m2;       //用来记录后面部分的数

int main()
{
    scanf("%lld", &n);
    
    //求出前缀和数组,并将所有数存入m2中
    scanf("%lld", &a[0]);
    m2[a[0]]++;
    sum[0] = a[0];
    for(int i = 1; i < n; i++){
        scanf("%lld", &a[i]);
        m2[a[i]]++;
        sum[i] = sum[i - 1] + a[i];
    }

    //枚举前后两部分,求解答案
    for(int i = 0; i < n; i++){
        m1[a[i]]++;                 //每遇到一个数就加到m1中
        m2[a[i]]--;                 //每遇到一个数就在m2中删去
        

        s1 = sum[i];                //前部分的和
        s2 = sum[n - 1] - sum[i];   //后部分的和

        if(s1 == s2){               //相等就不用移动了,直接输出
            printf("YES\n");
            return 0;
        }
        
        //看前后两部分是否有需要移动的那个数
        if(s2 - s1 > 0 && (s2 - s1) % 2 == 0 && m2[(s2 - s1) / 2] > 0){
            printf("YES\n");
            return 0;
        }

        if(s1 - s2 > 0 && (s1 - s2) % 2 == 0 && m1[(s1 - s2) / 2] > 0){
            printf("YES\n");
            return 0;
        }
    }

    printf("NO\n");

    return 0;
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值