CF808D 分割序列

1 CF808D 分割序列

2 题目描述

时间限制 \(2s\) | 空间限制 \(256M\)

Vasya has an array a consisting of positive integer numbers. Vasya wants to divide this array into two non-empty consecutive parts (the prefix and the suffix) so that the sum of all elements in the first part equals to the sum of elements in the second part. It is not always possible, so Vasya will move some element before dividing the array (Vasya will erase some element and insert it into an arbitrary position).

Inserting an element in the same position he was erased from is also considered moving.

Can Vasya divide the array after choosing the right element to move and its new position?

数据范围:\(1 ≤ n ≤ 100000, 1 ≤ a_i ≤ 10^9\)

3 题解

容易发现,把整个序列分成两个部分计算和可以利用前缀和计算。此时,将某一个左侧的数移动到右侧相当于将左侧的和减某个数,将右侧的和加某个数。那么我们想到,对于每一个时刻,我们求出左部和 \(lp(i)\) 与右部和 \(rp(i)\),然后判断此时左右部的差是否可以通过将某个左部的数移动到右边或者将某个右边的数移动到左边抵消。具体做法就是,使用两个 \(Map\) 将左、右部分所出现的数分别记录下来。然后当我们需要抵消时,判断较大的那一部分是否存在一个数使得另一部分加上两倍的该数正好等于当前部分。如果存在,那么直接输出 \(YES\)。否则如果我们在枚举完所有左部的元素个数后都不存在输出 \(YES\) 的情况,直接输出 \(NO\) 即可。

4 代码(空格警告):

#include <iostream>
#include <map>
using namespace std;
const int N = 1e5+10;
#define int long long
int n;
int a[N], sum[N];
map<int, int> M, M2;
int lp(int x) {return sum[x];}
int rp(int x) {return sum[n] - sum[x];}
signed main()
{
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i], sum[i] = sum[i-1] + a[i], M2[a[i]]++;
    M2[a[1]]--;
    for (int i = 1; i <= n; i++)
    {
        if (lp(i) == rp(i))
        {
            cout << "YES";
            return 0;
        }
        M[a[i]]++;
        if (lp(i) > rp(i) && !((lp(i) - rp(i)) % 2) && M[(lp(i) - rp(i))/2])
        {
            cout << "YES";
            return 0;
        }
        if (rp(i) > lp(i) && !((rp(i) - lp(i)) % 2) && M2[(rp(i) - lp(i))/2])
        {
            cout << "YES";
            return 0;
        }
        M2[a[i+1]]--;
    }
    cout << "NO";
    return 0;
}

欢迎关注我的公众号:智子笔记

posted @ 2021-04-05 12:20  David24  阅读(66)  评论(0编辑  收藏  举报