题意:p城有n家银行,第i个银行与第i+1,i-1个银行相邻,特殊的,1与n相邻,即这些银行形成了一个环。你在n家银行都有账户,并且n个账户上的钱数或正或负,但总和为0,现在你需要通过转账,将你的n个账户余额全部更改为0,求最小操作数。
思路:假设我们可以将这n家银行分成k段连续的区间,每个区间内银行余额和为0,那么我们只需对每个区间内进行移动即可,若第i个区间长度为
那么移动次数即为
,设总移动数为
,则有
对于k,我们可以用前缀和求出,具体方法是求出前缀和中出现次数最多的那个数字m出现的次数cnt即可,证明如下:
- 各前缀和都不同,那么就只有 一个连续子集的和为零,cnt = 1。
- 当前缀和出现重复时,cnt = 出现最多的前缀和的出现次数。
举个例子:
下标: 1 2 3 4 5 6 7 8 9
余额: 1 2 0 1 -1 2 1 -3 -3
前缀和: 1 3 3 4 3 5 6 3 0
对于该序列,3出现的四次,最多。 区间和为0,操作0次, 区间和为0,操作1次, 区间和为0,操作2次,剩下的1,2,9和为0,操作2次,共操作5次。满足ans = n - cnt。
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
map<ll ,int > mp;
int main(int argc, char const *argv[])
{
int n;
scanf("%d",&n);
ll sum = 0,x;
int cnt = 1;
for(int i=0;i<n;++i){
scanf("%I64d",&x);
sum += x;
mp[sum]++;
cnt = max(cnt,mp[sum]);
}
printf("%d\n",n-cnt);
return 0;
}