Description

小A有一个环,环上有n个正整数。他有特殊的能力,能将环切成k段,每段包含一个或者多个数字。对于一个切分方案,小A将以如下方式计算优美程度:
首先对于每一段,求出他们的数字和。然后对于每段的和,求出他们的最大公约数,即为优美程度。
他想通过合理地使用他的特殊能力,使得切分方案的优美程度最大。

Solution

很容易想到所有答案都是数字和的因数,而且答案会越来越小。
那么先分解质因数,然后判断这个质因数是否合法。
问题就在于怎么判断。
我们假设x可以整除l到r的和,那么就是sum[r]-sum[l-1]是合法的,那么很明显用前缀和去除以x,然后用hash来统计一个一个模数的出现次数,如果这个出现次数个个数大于i的话,那么i就可以为x。

Code

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<map>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=2007,mo=4*1e6+7;
ll i,j,k,l,t,n,m,pp;
ll ans[maxn],p[40000];
ll a[maxn],sum,ma[mo];
int h[mo][2];
int hash(ll x){
ll y=x%mo;
while(h[y][0]!=x&&h[y][0]!=0&&h[y][1]==i){
y=y+1;
if(y>=mo)y-=mo;
}
h[y][0]=x;
if(h[y][1]!=i)h[y][1]=i,ma[y]=0;
return y;
}
bool cmp(ll x,ll y){return x>y;}
int main(){
// freopen("fan.in","r",stdin);
// freopen("fan.out","w",stdout);
scanf("%lld",&n);
fo(i,1,n)scanf("%lld",&a[i]),sum+=a[i];
fo(i,1,sqrt(sum)){
if(sum%i==0){
p[++p[0]]=i;
if(i*i==sum)break;
p[++p[0]]=sum/i;
}
}
sort(p+1,p+p[0]+1,cmp);
l=1;
fo(i,1,p[0]){
k=0;
fo(j,1,n){
k=(k+a[j])%p[i];
pp=hash(k);
ma[pp]++;
t=max(ma[pp],t);
}
while(t>=l&&l<=n){
ans[l]=p[i];
l++;
}
}
fo(i,1,n){
printf("%lld\n",ans[i]);
}
}