codeforces 710D Two Arithmetic Progressions(线性同余方程)
题目链接:
http://codeforces.com/problemset/problem/710/D
分析:给你两个方程 a1k + b1 and a2l + b2,求在一个闭区间【L,R】中有多少个X,X满足 x = a1k' + b1 = a2l' + b2。
由此可以发现这两个方程满足线性同余,即 x ≡b1mod(a1) 且 x≡b2mod(a2); 也就是 a1k' + b1 = a2l' + b2a.
所以 a1k1 + (-a2k2) = (b2 - b1),由同余方程得 : X ≡ (b2 - b1) mod(a2).
所以我们可以先求的一个特解x0,然后找到它的最小整数解 x,再把x 放在【L,R】里找出它包含多少个。
对于解线性同余方程:
求特殊解
附:取模运算
int mod(int a,int b)
{
if(a >= 0)
return a % b;
else
return a % b + b;
}
线性同余方程
对于方程 a*x+b*y=n;有整数解得充分必要条件是(n %(a,b)==0),这个定理这里就不证明了,数论书上都有。
所以方程 a*x+b*y=n;我们可以先用扩展欧几里德算法求出一组x0,y0。也就是a*x0+b*y0=(a,b);然后两边同时除以(a,b),再乘以n。这样就得到了方程a*x0*n/(a,b)+b*y0*n/(a,b)=n;我们也就找到了方程的一个解。
还有一个定理:若(a,b)=1,且x0,y0为a*x+b*y=n的一组解,则该方程的任一解可表示为:x=x0+b*t,y=y0-a*t;且对任一整数t,皆成立。(这个证明比较简单,就不写了)
这样我们就可以求出方程的所有解了,但实际问题中,我们往往被要求去求最小整数解,所以我们就可以将一个特解x,t=b/(a,b),x=(x%t+t)%t;就可以了。
1 /************************************************************************* 2 > File Name: cf710D.cpp 3 > Author: 4 > Mail: 5 > Created Time: 2016年08月27日 星期六 22时28分30秒 6 ************************************************************************/ 7 8 #include<iostream> 9 #include<bits/stdc++.h> 10 using namespace std; 11 typedef long long ll; 12 13 ll exgcd(ll a, ll b, ll& x, ll& y) 14 { 15 ll d = a; 16 if(b!=0) 17 { 18 d = exgcd(b,a % b,y,x); 19 y -= (a / b) * x; 20 } 21 else 22 { 23 x = 1; 24 y = 0; 25 } 26 return d; 27 } 28 29 int main() 30 { 31 ll a1,b1,a2,b2,L,R; 32 cin >> a1 >> b1 >> a2 >> b2 >> L >> R; 33 ll x,y; 34 ll d = exgcd(a1,a2,x,y); 35 if((b2 - b1) % d != 0) 36 { 37 cout << 0 << endl; 38 return 0; 39 } 40 x *=(b2 - b1)/d; 41 ll t = a2/d; 42 x = (x % t + t) %t; 43 ll cnt = a1 * x + b1; 44 ll lcm = a1/d *a2; 45 ll ans = 0; 46 L = max(L,max(b1,b2)); 47 if(L > R) 48 { 49 cout << 0 << endl; 50 return 0; 51 } 52 if(cnt <= R) ans += (R-cnt)/lcm +1;//放在区间里找包含多少个解,需要注意方式 53 if(cnt < L) ans -= (L-cnt- 1)/lcm +1; 54 cout << ans << endl; 55 return 0; 56 }