【CodeForces - 1152C 】Neko does Maths(数学数论,lcm,gcd性质)
題干:
給出a,b<=1e9,你要找到最小的k使得lcm(a+k,b+k)盡可能小,如果有多個k給出同樣的最小公倍數,輸出最小的一個k。
解題報告:
因為題目中k太多了,先化簡一下公式,假設a>b ,則gcd(a+k,b+k) == gcd(a+k,a+b);
下面給出一個簡單證明:
z=gcd(a+k,b+k);
?所以:(a+k)%z==0,(b+k)%z==0;
? ?(a+k)%z==(b+k)%z;
? a%z+k%z=b%z+k%z;
故? (a-b)%z=0;
還有個一般化的結論: gcd(a,a) = gcd(a,a) gcd(a,b) = gcd(a,a-b)(a>b) gcd(a,b) = gcd(b,a-b)(a>b)
所以公式可以化為:
lcm(a+k,b+k) = (a+k)*(b+k) / gcd(a+k,b+k). 要使得lcm(a+k,b+k)最小,則需要gcd(a+k,b+k)最大
因此只需要枚舉(a-b)的因子將a+k湊至存在該因子fac(即a+k是fac的倍數),求出那個最小的k,(即k =(fac-a%fac)),取lcm最小值即可。
至于為什么k=fac-a%fac呢?下面給出簡要證明:
這是因為首先k<fac,(因為假設k>=fac有上述條件成立,則總可以通過k-=fac的操作使得k變小且原式依舊成立),且k是在這個條件下是唯一的(這個很顯然,不解釋了),所以在模fac的意義下肯定有a+k==0(mod fac),因此k=fac-a%fac,
AC代碼:
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define F first #define S second #define ll long long #define pb push_back #define pm make_pair using namespace std; typedef pair<int,int> PII; const int MAX = 2e5 + 5; ll a,b; vector<ll> vv; void solve(ll x) {//求出x的所有因子 for(ll i = 1; i*i<=x; i++) {if(x%i == 0) {vv.pb(i);if(i*i!=x) vv.pb(x/i);}} } ll lcm(ll a,ll b) {return a*b/__gcd(a,b); } int main() {cin>>a>>b;if(a < b) swap(a,b);//保證a>bll tmp = a-b,minn = lcm(a,b),ans=0;solve(tmp);int up = vv.size();for(int i = 0; i<up; i++) {ll k = vv[i] - a%vv[i];if(lcm(a+k,b+k) < minn) {minn = lcm(a+k,b+k);ans = k;}} cout << ans << endl;return 0 ; }?
總結
以上是生活随笔為你收集整理的【CodeForces - 1152C 】Neko does Maths(数学数论,lcm,gcd性质)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: sunasServ.exe - suna
- 下一篇: 118元起!中国广电5G套餐正式出炉:4