今早看到的题,想了下会做了,但是觉得这题挺有意思的,于是打算写一下做法。本题利用了gcd的基本性质:更相减损法以及结合律,平时做gcd的题基本没用到过这两性质,而本题对这性质进行了充分利用。
思路:
首先我们考虑给一个序列,我们该怎么做。
令
fn=∑ni=1ai
。
我们考虑序列的一个
k+1
划分
fx1,fx2−fx1,fx3−fx2,...,fn−fxk
,记为
{x1,x2,x3,...,xk−1,xk}
。
令
A=fx1,B=fx2−fx1,C=fx3−fx2
。
现在我们有
gcd
的两条基本但十分重要的性质:
1.
gcd
本质是更相减损法,即
gcd(A,B−A)=gcd(A,B)
。
2.
gcd
满足结合律,即
gcd(gcd(A,B),C)=gcd(A,gcd(B,C))
。
gcd(A,B-A,C-B)
=gcd(gcd(A,B-A),C-B)
=gcd(gcd(A,B),C-B)
=gcd(A,gcd(B,C-B))
=gcd(A,gcd(B,C))
=gcd(A,B,C)
根据数学归纳法,可以得出结论:序列上的任意一个
k+1
划分
{x1,x2,x3,...,xk−1,xk}
等价于
gcd(fx1,fx2,fx3,...,fxk,fn)
。
因为序列的任意一个划分总是包含
fn
,因此答案一定是
fn
的约数。
接下来,考虑枚举
gcd
的值
g
(即枚举答案,
了解了链上的做法,接下来考虑环上的做法。
考虑环上的断点为
现在考虑将断点向右移动
x
单位,即
然后枚举
gcd
的值
g
,然后计算
为了加速这一过程,考虑先枚举
其实无需真的枚举断点,换个角度思考,枚举断点等价于枚举
既然知道是什么原理了,最后总结一下做法:
1.枚举
gcd
的值
g
,
2.令
3.对
b数组
排序,然后统计相同的值出现的次数,
4.初始化
ans[]
,令值全为1,
5.假设值为
x
的出现了
6.对
ans
更新得后缀最大值。
for ( int i = n ; i >= 1 ; --i ) {
ans[i-1] = max ( ans[i - 1] , ans[i] ) ;
}
7.第
i
行输出