思路:数学枚举+环上问题
如果将环切成
k
k
k段,那么有
x
=
g
c
d
(
d
1
,
d
2
,
⋅
⋅
⋅
,
d
k
)
x=gcd(d_1,d_2,···,d_k)
x=gcd(d1,d2,⋅⋅⋅,dk)
我们可以发现
d
i
=
x
∗
k
i
d_i=x*k_i
di=x∗ki,因此
s
u
m
=
∑
d
i
=
x
∗
∑
k
i
sum=\sum d_i=x*\sum k_i
sum=∑di=x∗∑ki,我们发现
x
x
x是数组和的一个因子,由于
s
u
m
≤
1
0
11
sum\le10^{11}
sum≤1011,计算得到它的因子数大约
4000
4000
4000,因此我们可以考虑枚举
x
x
x
接下来我们考虑对于每个因子
x
x
x,如果前
i
i
i个数的和
s
u
m
i
sum_i
sumi和前
j
j
j个数的和
s
u
m
j
sum_j
sumj满足:
s
u
m
i
%
x
=
s
u
m
j
%
x
⇒
(
s
u
m
j
−
s
u
m
i
)
%
x
=
0
sum_i\%x=sum_j\%x\Rightarrow (sum_j-sum_i)\%x=0
sumi%x=sumj%x⇒(sumj−sumi)%x=0,因此区间
[
i
+
1
,
j
]
[i+1,j]
[i+1,j]的和是
x
x
x的倍数,那么由于是个环,我们可以知道剩余的数的和也是
x
x
x的倍数
那么如果对于某个因子
x
x
x,我们要得到尽可能多的区间个数
t
o
t
tot
tot,那显然我们需要统计前缀和
s
u
m
i
%
x
sum_i\%x
sumi%x等于哪个数时的个数最多,最多的个数即为我们对于这个因数
x
x
x所能划分的最多区间个数
t
o
t
tot
tot,显然区间个数小于
t
o
t
tot
tot时这个因数
x
x
x都是符合的
那我们要求每个
k
k
k对应的最大公约数,只需要求个后缀最大即可
#include <bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define endl '\n';
typedef long long ll;
typedef pair<int,int> PII;
const int N=1e6+10,mod=1e9+7;
ll n,a[N],sum[N],ans[N];
void solve(ll x){
ll tt=0;
map<ll,ll>mp;
for(int i=1;i<=n;++i){
mp[sum[i]%x]++;
tt=max(tt,mp[sum[i]%x]);
}
ans[tt]=max(ans[tt],x);
}
int main(){
IOS;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i];
int len=sqrt(sum[n]);
for(int i=1;i<=len;i++){
if(sum[n]%i==0){
solve(i);
solve(sum[n]/i);
}
}
for(int i=n-1;i>0;i--) ans[i]=max(ans[i],ans[i+1]);
for(int i=1;i<=n;++i) cout<<ans[i]<<endl;
return 0;
}