Educational Codeforces Round 21 D - Array Division (前缀和+二分)

传送门

题意

将n个数划分为两块,最多改变一个数的位置,
问能否使两块和相等

分析

因为我们最多只能移动一个数x,那么要么将该数往前移动,要么往后移动,一开始处理不需要移动的情况
那么遍历sum[i]
如果往前移动,sum[k]+(sum[i]-sum[i-1])=sum[n]/2,k∈[1,i-1]
如果往后移动,sum[k]-(sum[i]-sum[i-1])=sum[n]/2,k∈[i+1,n]
一开始我没有考虑往后移动
时间复杂度\(O(nlog(n))\)

trick

代码

#include<cstdio>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
int n;
ll sum[100100];
ll ans,x;

bool find(int l,int r,ll val)
{
    while(l<=r)
    {
        int mid=(l+r)/2;
        if(val<sum[mid]) r=mid-1;
        if(val>sum[mid]) l=mid+1;
        if(val==sum[mid]) return 1;
    }
    return 0;
}
int flag=0;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    {
        scanf("%lld",&x);
        sum[i]=sum[i-1]+x;
    }
    if(sum[n]&1) { puts("NO");return 0; }
    ans=sum[n]/2;
    //if(find(1,n,ans)) {flag=1;goto loop;}
    for(int i=1;i<=n;++i)
    {
        ll ret=sum[i]-sum[i-1]+ans;
        if(find(i+1,n,ret)) { flag=1;break; }
        ret=ans-(sum[i]-sum[i-1]);
        if(find(1,i-1,ret)) { flag=1;break; }
    }
    //if(find(1,n-2,sum[n-1]-ans)) flag=1;
    loop:
    flag?puts("YES"):puts("NO");
}
posted @ 2017-05-16 22:03  遗风忘语  阅读(174)  评论(0编辑  收藏  举报