Two Arithmetic Progressions (exgcd的一些注意事项
题意:You are given two arithmetic progressions: a1k + b1 and a2l + b2. Find the number of integers x such that L ≤ x ≤ R and x = a1k' + b1 = a2l' + b2, for some integers k', l' ≥ 0。
分析:
化为 a1k - a2l = b2- b1 ,求解二元一次不定方程,看正整数解x,y分别代入后有多少落在L,R之间,取最小的为答案即可
but,思路很简单的一道题,却因为以下错误debug了一上午
1, Q:ax - by =c 与 ax + by =c 解的不同
觉得这两个一样,所以写的 exgcd( a1 ,a2 ,b2-b1 ,x ,y)
事实是:对于求x的最小正整数解,这两个是一样的 ,对于求y的最小正整数解,这两个不一样
所以这道题 应该写成exgcd( a1 ,-a2 ,b2-b1 ,x ,y)
2,c++对于负数的取余规则
c++取余结果是这样的 : a%b = (a的符号)(abs(a)%abs(b)),这跟数论负数取余规则不一样,所以要避免对负数取余情况的发生
bool lieu( ll a ,ll b ,ll c ,ll &x ,ll &y ){ g = ex_gcd( a ,b ,x ,y ); if( c%g ) return 0; ll k = c/g ; mb = abs(a/g) ,ma = abs(b/g); x *= k; y *= k; x = (x%ma + ma)%ma; y = (y%mb + mb)%mb; return 1; }
开始没注意通解的模ma,mb的正负, 以后这个模板这里都要加abs()
#include <bits/stdc++.h> #define mem( a ,x ) memset( a ,x ,sizeof(a)) #define rep( i ,x ,y ) for( int i = x ; i <= y ; i++ ) using namespace std; typedef long long ll; ll L ,R ,n ,a1 ,a2 ,b1 ,b2; ll g ,ma ,mb; ll ex_gcd( ll a ,ll b ,ll &x ,ll &y ){ if( !b ){ x = 1; y = 0; return a; } ll d = ex_gcd( b ,a%b ,x ,y ); ll t = x; x = y; y = t - a/b * y; return d; } bool lieu( ll a ,ll b ,ll c ,ll &x ,ll &y ){ g = ex_gcd( a ,b ,x ,y ); if( c%g ) return 0; ll k = c/g ; //模板修正 :加abs mb = abs(a/g) ,ma = abs(b/g); x *= k; y *= k; x = (x%ma + ma)%ma; y = (y%mb + mb)%mb; return 1; } int main( ){ ll ans1 = 0 ,ans2 = .0; cin >>a1 >>b1 >>a2 >>b2 >>L >>R; ll x ,y ,l1 ,r1 ,l2 ,r2; //cout<< (-6)%4 <<endl; if( lieu(a1 ,-a2 ,b2-b1 ,x ,y ) ){ x = a1*x + b1; y = a2*y + b2; ma = abs(ma*a1); mb = abs(mb*a2); l1 = max( 1ll*0 ,L - x) ,r1 = R - x; l2 = max( 1ll*0 ,L - y) ,r2 = R - y; if( r1 >=0 ){ l1 = (l1/ma*ma) < l1 ? (l1/ma*ma)+ma : (l1/ma*ma); r1 = (r1/ma*ma); ans1 = (r1-l1)/ma+1; } if( r2 >=0 ){ l2 = (l2/mb*mb) < l2 ? (l2/mb*mb)+mb : (l2/mb*mb); r2 = (r2/mb*mb); ans2 = (r2-l2)/mb+1; } } printf("%lld" ,min( ans2 ,ans1) ); return 0; }