Codeforces 354C Vasya and Beautiful Arrays

問題

数列a[i]が与えられる。
それぞれの項から、引いた後0以下にならないように最大kを引くことができる。


なるべく出来た数列の最大公約数を大きくしたい。
最大値を求めよ。

制約条件

a[i]≦10^6
n≦3*10^5

方針

パソコン甲子園のモジュロ・クエリ(そのままの解法が使える)だった。
http://web-ext.u-aizu.ac.jp/pc-concours/2013/programming/p_pastexam.html
(2012年本選5)
なんか見たことある問題だと思った。


まず数列aはuniqueしてよい。
最大公約数qを決めうちして作れるか調べる。


モジュロクエリと同様にして、L[i]という配列を作ってai未満の最大のajをO(1)で求めることができれば、
計算量O(A / q)でai%qの最大値が求まる。(Aはmax{a[i]})


これを全てのqについて調べると、計算量はA / 1 + A / 2 + A / 3 + ... + A / A = O(AlogA)
a[i]を0にしてしまってはいけないことにだけ注意する。

ソースコード

int n, k, a[300000], l[1000100];

int main(){
	
	cin >> n >> k;
	rep(i, n) cin >> a[i];
	sort(a, a + n);
	n = unique(a, a + n) - a;
	
	l[0] = -1;
	for(int i = 0, j = 0; j <= 1000010; j++){
		if(i < n && a[i] == j) l[j + 1] = a[i++];
		else l[j + 1] = l[j];
	}
	
	for(int i = a[0]; i > 1; i--){
		bool ok = 1;
		
		for(int j = a[n-1]; j >= a[0]; ){
			if(j % i > k || j == a[0] && j < i){
				ok = 0;
				break;
			}
			j -= j % i;
			j = l[j];
		}
		
		if(ok){
			cout << i << endl;
			return 0;
		}
	}
	cout << 1 << endl;
	return 0;
}