今早看到的題,想了下會做了,但是覺得這題挺有意思的,於是打算寫一下做法。本題利用了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 (即枚舉答案,fn 的約數),即fn 的約數(不超過1e4 個),然後計算fimodg=0 的個數,假設爲x 個,則說明1 ~x 的劃分的答案均可爲此值。
瞭解了鏈上的做法,接下來考慮環上的做法。
考慮環上的斷點爲n 和1 之間,記爲0 ,則答案即鏈上求得的答案。
現在考慮將斷點向右移動x 單位,即fx 屬於最後一個區間,且1 ~x 之間不可能再有斷點,否則我們在之前便已枚舉過。
然後枚舉gcd 的值g ,然後計算x+1 ~n 內滿足fymodg=fxmodg 的y 的個數。
爲了加速這一過程,考慮先枚舉gcd 的值g ,再枚舉斷點x ,然後看斷點之後滿足fymodg=fxmodg 的y 的個數。
其實無需真的枚舉斷點,換個角度思考,枚舉斷點等價於枚舉fxmodg 的值,而每個fxmodg 的值只有編號最小的有用,因爲在這樣的x 之後的y 纔會儘可能多。
既然知道是什麼原理了,最後總結一下做法:
1.枚舉gcd 的值g ,
2.令bi=fimodg ,
3.對b數組 排序,然後統計相同的值出現的次數,
4.初始化ans[] ,令值全爲1,
5.假設值爲x 的出現了y 次,則令ans[y]=max(ans[y],x) ,
6.對ans 更新得後綴最大值。
for ( int i = n ; i >= 1 ; --i ) {
ans[i-1] = max ( ans[i - 1] , ans[i] ) ;
}
7.第i 行輸出ansi 。