给出N个固定集合{1,N},{2,N-1},{3,N-2},...,{N-1,2},{N,1}.求出有多少个集合满足:第一个元素是A的倍数且第二个元素是B的倍数。
提示:
对于第二组测试数据,集合分别是:{1,10},{2,9},{3,8},{4,7},{5,6},{6,5},{7,4},{8,3},{9,2},{10,1}.满足条件的是第2个和第8个。
Input
第1行:1个整数T(1<=T<=50000),表示有多少组测试数据。 第2 - T+1行:每行三个整数N,A,B(1<=N,A,B<=2147483647)
Output
对于每组测试数据输出一个数表示满足条件的集合的数量,占一行。
Input示例
2 5 2 4 10 2 3
Output示例
1 2
思路:利用 扩展欧几里得算法算得最小的非负整数解x ,那么x每加一个 最小公倍数就是一个解。
由题意知 Ax+By=N+1 , 而 扩展欧几里得 Ax+By=gcd(A,B) 可求得 gcd(A,B), 通解 x,y;
那么 对于 Ax+By=N+1,通解 x0=x*((N+1)/gcd(A,B)), 在 利用 x=x0-(B/gcd(A,B))*t 求出最小的非负整数解 即可
Code:
#include<iostream>
using namespace std;
typedef long long LL;
LL n,A,B,T;
/*
Ax+By=gcd(A,B)
x = x0 + (b/gcd)*t
y = y0 –(a/gcd)*t
*/
LL exgcd(LL a,LL b,LL &x,LL &y);
int main()
{
ios::sync_with_stdio(false);
cin>>T;
while(T--){
cin>>n>>A>>B;
LL ans=0,x,y;
LL gcd=exgcd(A,B,x,y);
LL lcm=A/gcd*B; //最小公倍数
if((n+1)%gcd==0){
LL x0=x*((n+1)/gcd);
LL tt=(x0%(B/gcd)+B/gcd)%(B/gcd); //x0可能为负数
if(!tt) tt=B/gcd;
LL sum=n-tt*A;
if(sum<0) ans=0;
else ans=sum/lcm+1;
}
cout<<ans<<endl;
}
return 0;
}
LL exgcd(LL a,LL b,LL &x,LL &y)
{
if(!b){
x=1; y=0;
return a;
}
LL t,ans=exgcd(b,a%b,x,y);
t=x; x=y; y=t-a/b*y;
return ans;
}