CF1152C Neko does Maths

題目描述

(描述爲翻譯,翻譯來自洛谷)
給定兩個正整數a,b,找到非負整數k使a+k與b+k的最小公倍數最小,如有多解輸出最小的k

a,b106a ,b ≤ 10^6
對於這種題我們顯然需要一些數論知識來幫助我們找到思路
那麼我們首先想到的是lcm和gcd是有關係的
lcm(a,b)=abgcd(a,b)lcm(a,b) = \frac{a*b}{gcd(a,b)}
那麼在這道題中就是lcm(a+k,b+k)=(a+k)(b+k)gcd((a+k),(b+k))lcm(a+k, b+k) = \frac{(a+k) * (b+k)}{gcd((a+k), (b+k))}
然後我們可以想到gcd的一些性質
那麼由更相減損術我們可以知道gcd(a,b)=gcd(b,ab)gcd(a,b) = gcd(b,a-b)其中,a >b;
那麼我們就可以把原式子中的gcd(a+k,b+k)gcd(a+k,b+k)寫成gcd(b+k,ab)gcd(b+k, a-b)
那麼我們考慮,設 x=gcd(b+k,ab)x = gcd(b+k, a-b)那麼x一定是a-b的因子的其中一個,這時候我們只需要算出一個k使x是b+k和a-b的gcd我們就可以求出一個lcm,
這裏當bmod  x==0b\mod x == 0時k = 0;
!=時 k = b/x * x + x; 這裏的除是向下取整,這樣就保證了x是b+k的最大因子。
因此我們可以枚舉a-b的所有因子,求出對應的k和lcm,對於每個結果進行比較求min即可。

沒想到的是,k是會爆ll的 所以記得開ll寫

CodeCode

#include<bits/stdc++.h>

#define INF 0x3f3f3f3f
#define ll long long

using namespace std;

inline ll gcd(ll a, ll b){//沒用
	return a % b == 0 ? b : gcd(b, a % b);
}


ll a, b, k, t;
ll ans = 1e18;

int main()
{
	cin >> a >> b;
	if(a < b){
		a ^= b, b ^= a, a ^= b;
	}
	ll num = 1e18;
	
	for(ll i = 1; i * i <= a-b; ++i){//i,j都爲枚舉的因子
		ll tk;
		if((a-b) % i == 0){
			ll j = (a-b) / i;
			
			if(b % i == 0) tk = 0;
			else tk = (b / i + 1) * i - b;
			
			ll num = (a + tk) * (b + tk) / i;
			
			if(num < ans) ans = num, k = tk;
			if(num == ans) k = min(k, tk);

			if(b % j == 0) tk = 0;
			else tk = (b/j + 1) * j - b;
			
			num = (a + tk) * (b + tk) / j;
			if(num < ans) ans = num, k = tk;
			
			else if(num == ans) k = min(k, tk);
		}
	}
	cout << k << endl;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章