CF 675C Money Transfers

来源:互联网 发布:南风知我意在线阅读 编辑:程序博客网 时间:2024/05/01 05:24

题目大意:有n个银行编号为1-n,n视作与1相邻,每个银行有ai(1e9ai1e9)的存款。有一种操作,相邻编号的银行可以转任意多的钱。使每个银行的存款都为0的最小操作数是多少。保证ni=1ai=0

题解:
1.每个相邻的银行之间最多发生一次转移,因此最多转移次数为n次。
2.若能分成k段不相交的和为0的区间,则只有区间内部的银行需要转移,而相邻的区间之间不需要转移,即减少了k次转移。
3. 因此只需要将银行分成最多的和为0的区间,在区间内部转移即可。问题变成求最大的不相交和为0的区间数。
和为0的区间实际上是两段前缀和相同的区间的差,因此只要统计相同的前缀和的个数,每一种前缀和对应的是一个和为0的区间划分。若有k个前缀和相同,由于是环形的,因此该划分分成了k个和为0的区间。找到最大的划分方案数k,那么n-k就是答案。

#include <cstdio>#include <vector>#include <queue>#include <cstring>#include <algorithm>using namespace std;const int maxn = 200020;const int inf = 0x3f3f3f3f;typedef long long ll;vector<pair<ll,int> > HasH[maxn];ll a[maxn];int main(){    int n;    scanf("%d",&n);    for(int i= 0;i < n;i++) scanf("%I64d",&a[i]);    int ans = n;    int k = (a[0]%maxn+maxn)%maxn;    HasH[k].push_back(pair<ll,int>(a[0],1));    for(int i = 1;i < n;i++){        a[i] += a[i-1];        k = (a[i]%maxn+maxn)%maxn;        int flag = 1;        for(int j = 0;j < HasH[k].size();j++){            pair<ll,int> t = HasH[k][j];            if(t.first == a[i]){                HasH[k][j].second++;                break;            }        }        HasH[k].push_back(pair<ll,int>(a[i],1));    }    int cnt = 0;    for(int i = 0;i < maxn;i++){        for(int j = 0;j < HasH[i].size();j++){            cnt = max(HasH[i][j].second,cnt);            //printf("%d\n",HasH[i][j].second);        }    }    printf("%d\n",ans-cnt);    return 0;}
0 0