题意:给定和为0的n个数a[1]~a[n],形成环即a[1]与a[n]相邻,操作:每个位置的数能向它相邻的位置转移。求最后变成全0最少需要转移多少次。
分析:这题在比赛的时候卡了很多人,这个建模思想在大白书前两页就有,稍微有一点点变形,没看过的同学试着看看我写的分析吧。我们设第i的位置a[i]向它前面那个位置转移了xi,显然每个位置最多转移1次即答案<=n,且最后的值为0,所以我们能得到n个等式:a[i]-x[i]+x[i+1]=0。这有什么用呢?我们将这些等式变形得:x[1]=x[1],a[1]-x[1]+x[2]=0-->x[2]=x[1]-a[1],a[2]-x[2]+x[3]=0-->x[3]=x[2]-a[2]=x[1]-a[1]-a[2],x[4]=x[1]-a[1]-a[2]-a[3]。。x[n]=x[1]-a[1]-a[2]-a[3]...-a[n-1]。我们令c[i]=a[1]+a[2]+..+a[i-1]。那么有x[1]=x[1]-c[1],x[2]=x[1]-c[2],x[3]=x[1]-c[3]。。。x[n]=x[1]-c[n]。当我们得到了这n个等式之后我们考虑一下题目要我们求什么,未变动的位置最多即x[i]=0的位置最多。那么我们只要令x[1]为c数组的众数就好啦。详见代码。
代码:
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=100010;
const int MAX=1000000100;
const int mod=100000000;
const int MOD1=1000000007;
const int MOD2=1000000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=998244353;
const int INF=1000000010;
typedef double db;
typedef unsigned long long ull;
int g[N];
ll a[N],f[N];
int main()
{
int i,n,ans=INF;
scanf("%d", &n);
for (i=1;i<=n;i++) scanf("%I64d", &a[i]);
for (i=2;i<=n;i++) f[i]=f[i-1]+a[i];
sort(f+1,f+n+1);
g[1]=1;
for (i=2;i<=n;i++)
if (f[i]==f[i-1]) g[i]=g[i-1]+1;
else g[i]=1;
for (i=1;i<=n;i++) ans=min(ans,n-g[i]);
printf("%d\n", ans);
return 0;
}