1. 程式人生 > >HPU 1046: QAQ的數學問題 【貝祖定理】

HPU 1046: QAQ的數學問題 【貝祖定理】

1046: QAQ的數學問題 [數學]

時間限制: 1 Sec  記憶體限制: 128 MB
提交: 61  解決: 11
[提交][狀態][討論版]

題目描述

QAQ很喜歡數學,尤其對LCMLCM(最小公倍數)很感興趣。
對於數對(6,10)(6,10),可以得出LCM(6,10)=30LCM(6,10)=30。為了讓LCMLCM的值最小化,他嘗試把661010全部加上22,這樣得到LCM(8,12)=24<30LCM(8,12)=24<30
經過無數次的嘗試,QAQ發現總是可以通過上面相加的方式(必須加的是非負整數)讓LCMLCM的值達到最小的,但是他忘記至少需要加多少了,所以你來請幫幫他吧。

輸入

第一行輸入一個整數TT,代表有TT組測試資料。

每組資料輸入兩個整數A,BA,B,分別代表上面提到資訊。

注:1<=T<=20001<=AB<=20000000001<=T<=2000,1<=A,B<=2000000000

輸出

對每組資料,輸出一個結果,代表QAQ至少需要加的數。

樣例輸入

3
6 10
4 10
3 10

樣例輸出

2
2
4

來源

CZY

題解:

因為A和B的差始終是不變的,那麼考慮差對結果的影響。

發現不管怎麼變,GCD(A,B)就是abs(A−B)的一個因子。

我們預處理因子,然後列舉因子維護最優解即可。

時間複雜度O(T∗log(abs(A−B)))。

AC程式碼:

#include<cstdio>
#include<cmath>
#include<algorithm>

using namespace std;

typedef long long LL;

int f[10111];

LL GCD(LL a,LL b) {
	return !b?a:GCD(b,a%b);
}
LL LCM(LL a,LL b) {
	return a/GCD(a,b)*b;
}

int main() {
	LL T; scanf("%lld",&T);
	while(T--) {
		LL a,b; scanf("%lld%lld",&a,&b);
		if(a<b) swap(a,b);
		LL m=a-b,i,cnt=0;
		for( i=1;i*i<m;++i) {
			if(m%i==0) {
				f[cnt++]=i; f[cnt++]=m/i; 
			}
		}
		if(m%i==0) f[cnt++]=i;
		LL ans=LCM(a,b),x=0;
	    for(i=0;i<cnt;++i) {
	    	LL j=f[i]-b%f[i];//求b對於f[i]的逆 不要用while去找 會T 
			LL tem=(a+j)/f[i]*(b+j);
			if(tem<ans) {
				ans=tem; x=j;
			}
		} 
		printf("%lld\n",x);
	}
 	return 0;
}