TopCoder SRM 505 Div1 Medium SetMultiples

問題

整数を要素とする二つの集合S1,S2があったとき、
S2がS1の倍数であるとは、S1のどんな要素xに対しても、
ある整数kおよびS2の要素yが存在して、y=x*kが成り立つことを言う。


Sを、A<=x<=BまたはC<=x<=Dを満たす整数の集合とする。
Sの倍数であるような集合のうち、要素の数が最小であるようなものの、要素の個数を求めよ。

制約条件

A,B,C,D≦10^10

方針

区間[C,D]のうち、D/2以下の整数は、その倍数が[D/2+1,D]に含まれているため、
C=max(C,D/2+1)としてよい。
同様に、A=max(A,B/2+1)としてよい。


区間[A,B]から、[C,D]にその倍数を持つ数を削っていく。
B以下の最も大きい数になるようCをある整数kで割る。
これはC/k≦B⇔C/B≦kより、C/Bを切り上げた数をkとすればよい。


C/k(を切り上げた整数)以上D/k以下の整数については、区間[C,D]に倍数となる整数が存在するため、消すことができる。


B=C/k(を切り上げた整数)-1として、以上のプロセスを更新がなくなるまで続ければよい。

ソースコード

class SetMultiples {
	public:
	long long smallestSubset(long long A, long long B, long long C, long long D) 
	{
		C=max(C,D/2+1);
		A=max(A,B/2+1);
		ll ans=D-C+1+B-A+1;
		while(A<=B){
			ll k=(C+B-1)/B;
			ll s=(C+k-1)/k, t=D/k;
			ans-=max(0ll,min(B,t)-max(A,s)+1);
			B=s-1;
		}
		return ans;
	}
};