Description
小A有一个环,环上有n个正整数。他有特殊的能力,能将环切成k段,每段包含一个或者多个数字。对于一个切分方案,小A将以如下方式计算优美程度:
首先对于每一段,求出他们的数字和。然后对于每段的和,求出他们的最大公约数,即为优美程度。
他想通过合理地使用他的特殊能力,使得切分方案的优美程度最大。
Solution
这题很显然答案一定是 ∑ni=1ai 约数。
然后我们就可以愉快的枚举约数,接着我们考虑怎么分段。
不在环上的做法,我们设枚举的约数为
d
,那么我们做一次
那么环上是不是就要考虑把头尾区间合并呢?
我们发现其实并不需要,因为在环上,我们显然可以将前面多余的一段补到后面去,那么分段就是完整的了。抽象来说,你现在要在序列中间放隔板,因为在环上,所以放了多少个隔板就有多少段。
最后答案取个后缀最大值即可。
1011 以内的约数不超过5000个。
Code
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define N 2010
#define mo 4000007
#define ll long long
using namespace std;
ll f[N][N];
int a[N],b[N];
ll c[N];
ll ys[N*10];
ll h[mo],zz[mo];
int n;
ll hash(ll x)
{
ll p=x%mo;
while(h[p] && h[p]!=x) p=(p+1)%mo;
return p;
}
int g[mo];
void work(ll x)
{
ll s=0,z=0;
g[0]=0;
fo(i,1,n)
{
s=(s+a[i])%x;
ll p=hash(s);
g[++g[0]]=p;
h[p]=s;
zz[p]++;
z=max(z,zz[p]);
}
c[z]=max(c[z],x);
fo(i,1,g[0]) h[g[i]]=zz[g[i]]=0;
}
int main()
{
scanf("%d",&n);
ll ss=0;
fo(i,1,n) scanf("%d",&a[i]),ss+=a[i];
for(ll i=1;i*i<=ss;i++)
if(ss%i==0)
{
ys[++ys[0]]=i;
if(ss/i!=i) ys[++ys[0]]=ss/i;
}
fo(i,1,ys[0]) work(ys[i]);
fd(i,n-1,1) c[i]=max(c[i],c[i+1]);
fo(i,1,n) printf("%lld\n",c[i]);
}