kmjp's blog

競技プログラミング参加記です

Codeforces #304 Div2 D. Soldier and Number Game

またcoutにやられた。
http://codeforces.com/contest/546/problem/D

問題

A,BからなるクエリがT個与えられる。
A!/B!を2以上の数で何回割ることができるか求めよ。

解法

Ω(x)をxの重複を含めた素因数の個数とする。

各クエリはΩ(A!)-Ω(B!)を求めればよい。
A≦5000000なので、先にΩ(x!)を5000000まで列挙しておけば、各クエリO(1)で終わる。
Ω(x!)=Ω(x) + Ω((x-1)!)より、Ω(x)を列挙すればΩ(x!)も容易に求められる。

問題はクエリ数が10^6と多いこと。
cout-endlをこの回数繰り返すとTLEするので、endlを避けたりprintfにする対応が必要。

int T;
ll A,B;

const int prime_max = 5200000;
int NP,prime[1100000],divp[prime_max];
ll num[5050500];
ll sum[5050500];

void cprime() {
	for(int i=2;i<prime_max;i++) if(divp[i]==0) {
		for(int j=i*2;j>i&&j<prime_max;j+=i) divp[j]=i;
	}
}

void solve() {
	int i,j,k,l,r,x,y; string s;
	
	cprime();
	
	for(i=2;i<=5000000;i++) {
		if(divp[i]==0) num[i]=1;
		else num[i]=num[i/divp[i]]+1;
		sum[i] = sum[i-1]+num[i];
	}
	
	cin>>T;
	while(T--) {
		cin>>A>>B;
		_P("%d\n",(int)(sum[A]-sum[B]));
	}
}

まとめ

10^5はまだしも、10^6の出力はendlを使っていはいけないことは覚えておかなくては。