洛谷题目页面传送门 & CodeForces题目页面传送门
有(2)个等差数列(A:A_i=a_1i+b_1(iinmathbb N),B:B_i=a_2i+b_2(iinmathbb N))。给定(l,r),求有多少个整数(nin[l,r])满足(n)既在(A)内又在(B)内。
(a_1,a_2inleft(0,2 imes10^9 ight]capmathbb Z,b_1,b_2,l,rinleft[-2 imes10^9,2 imes10^9 ight]capmathbb Z,lleq r)。
设(n)在(A)中是第(xinmathbb N)项,在(B)中是第(yinmathbb N)项,则可以列出不定方程
转化成标准形式,得
这个显然可以用Exgcd先确定无解并输出(0)走人,或确定有解并得到一组特解(egin{cases}x=x'\y=y'end{cases})。令(Delta x=dfrac{a_2}{gcd(a_1,a_2)},Delta y=dfrac{a_1}{gcd(a_1,a_2)}),则通解是(egin{cases}x=x'+kDelta x\y=y'+kDelta yend{cases}(kinmathbb Z))。但对于(x,y)还有一个特殊的条件,就是(x,yinmathbb N)。不难发现(x,y)同增同减,不妨找到使得(x,y)都最小的一组解(egin{cases}x=x''\y=y''end{cases})。(x,y)都最小,当且仅当(x-Delta x<0)或(y-Delta y<0),于是分别令(x''=x'mod Delta x,y''=y'mod Delta y),每次带入原方程解出另一个变量看是否(geq0),必有一次合法。
现在知道了(x'',y''),通解就变成了(egin{cases}x=x''+kDelta x\y=y''+kDelta yend{cases}(kin mathbb N))。将(x=x''+kDelta x)带入(a_1x+b_1in[l,r])得
即
即
即
又因为(kinmathbb N),所以
然后算出(k_{min},k_{max}),(max(0,k_{max}-k_{min}+1))就是答案。
最后吐槽一下,C++中的/
号是向零取整,也就是(<0)时上取整、(geq0)时下取整,(k)的解集中如果直接用/
号算会WA,然后心态爆炸。所以必须要将被除数和除数统一取绝对值,然后利用(leftlfloordfrac ab
ight
floor+leftlceildfrac {-a}b
ight
ceil=0)这个原理计算,最后该取相反数取相反数:
int quo_floor(int x,int y){return (x<0)^(y<0)?-(abs(x)+abs(y)-1)/abs(y):x/y;}
int quo_ceil(int x,int y){return (x<0)^(y<0)?-abs(x)/abs(y):(x+y-1)/y;}
下面贴AC代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int quo_floor(int x,int y){return (x<0)^(y<0)?-(abs(x)+abs(y)-1)/abs(y):x/y;}//下取整
int quo_ceil(int x,int y){return (x<0)^(y<0)?-abs(x)/abs(y):(x+y-1)/y;}//上取整
int exgcd(int a,int b,int &x,int &y){//Exgcd
if(!b)return x=1,y=0,a;
int d=exgcd(b,a%b,y,x);
return y-=a/b*x,d;
}
int a1,a2,b1,b2,l,r;//题目给的参数
signed main(){
cin>>a1>>b1>>a2>>b2>>l>>r;
int x,y,gcd=exgcd(a1,-a2,x,y);
if((b2-b1)%gcd)return puts("0"),0;//无解
x*=(b2-b1)/gcd;y*=(b2-b1)/gcd;//找到特解
int dx=abs(a2/gcd),dy=abs(a1/gcd);
((x%=dx)+=dx)%=dx;y=(a1*x-(b2-b1))/a2;
if(y<0)((y%=dy)+=dy)%=dy,x=(a2*y+(b2-b1))/a1;//找到使x,y都最小的解
int l0=max(0ll,quo_ceil(l-a1*x-b1,a1*dx)),r0=quo_floor(r-a1*x-b1,a1*dx);//k[min],k[max]
cout<<max(0ll,r0-l0+1);//答案
return 0;
}