Codeforces 466C Number of Ways 二分

来源:互联网 发布:windows 7 启动过程 编辑:程序博客网 时间:2024/05/16 10:49

点击打开链接

//题意:把数列a分成相等的三部分S(1,i-1)=S(i,j)=S(j+1,n) 求断点(i,j)的选法个数 

//3*x=sum,假设当前找到pre[i-1]=x 则只要找到下标j>=i&&pre[j]=2x 的个数即可,剩下(j+1,s)=3x-2x=x; 
//保存pre[j]=2x的下标 当pre[i-1]==x时二分出第一个>i-1的j即可 

O(nlogn)

#include <bits/stdc++.h>using namespace std;typedef long long ll;const ll mod=1e9+7;const int N=5e5+20;ll a[N],pre[N];vector<int> pos; int main(){int n;while(cin>>n){ll ans=0,sum=0; memset(pre,0,sizeof(pre));for(int i=1;i<=n;i++){scanf("%I64d",&a[i]);pre[i]=pre[i-1]+a[i];sum+=a[i];}ll x;if(sum%3){puts("0");continue;}x=sum/3;for(int i=1;i<n;i++)//第二段端点j要求i<=j<n {if(pre[i]==x*2) {pos.push_back(i);}}for(int i=2;i<n;i++){if(pre[i-1]==x){ //abs(a[i])<=1e9 pre[j]=2x,pos中下标j是有序的int cnt=pos.end()-upper_bound(pos.begin(),pos.end(),i-1);//找到第一个大于i的下标 ans+=cnt; }}cout<<ans<<endl;pos.clear();}return 0;}
标程的做法 O(n)

#include <iostream>#include <math.h>using namespace std;int a[1000010];long long cnt[1000010];int main(){    ios::sync_with_stdio(0);    int n;    cin >> n;    long long s = 0;    for(int i = 0 ; i < n ; ++i)    {        cin >> a[i];        s += a[i];    }    if (s % 3 != 0)        cout << "0\n";    else {        s /= 3;        long long ss = 0;        for(int i = n-1; i >= 0 ; --i)        {            ss += a[i];            if (ss == s)                cnt[i] = 1;        }        for(int i = n-2 ; i >= 0 ; --i)            cnt[i] += cnt[i+1];                long long ans = 0;        ss = 0;        for(int i = 0 ; i+2 < n ; ++i) {            ss += a[i];            if (ss == s)                ans += cnt[i+2];        }        cout << ans << "\n";    }    return 0;}





0 0
原创粉丝点击