版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sxh759151483/article/details/81705976
给出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
首先很容易可以看出是一个求ax + by = c的所有整数解的题(a = A, b = B, c = n + 1)。
假如先求出x的最小解为x0,那么x的每个解(x1,x2.....xm)之间的差为b / gcd(a,b).
那么只需要知道x的最大解xm就可以得出解的个数ans = (xm - x0)/ (b / gcd);
x的最大解:假如知道y的最小解y0,那么x的最大解xm = (c - y * b) / a;
所以可以先用扩展欧几里得求出x和y的最小解x0、y0
那么ans = (c - yb - ax)/ (a * b / gcd(a,b));
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll exgcd(ll a,ll b,ll &x,ll &y){
if(!b){
x=1;y=0;
return a;
}
ll ans=exgcd(b,a%b,x,y);
ll temp=x;
x=y;
y=temp-a/b*y;
return ans;
}
ll cal(ll a,ll b,ll c) {//求扩展欧几里德
ll x,y;
ll gcd = exgcd(a,b,x,y);
if(c%gcd!=0) return -1;//无解
x*=c/gcd;
b/=gcd;
return (x%b+b)%b;
}
int main()
{
int T;
ll n, a, b, c;
scanf("%d", &T);
while(T--){
scanf("%lld%lld%lld", &n, &a, &b);
c = n + 1;
ll gcd = __gcd(a, b);
ll t = b / gcd;
ll x = cal(a, b, c);
ll y = cal(b, a, c);
y = y == 0 ? a / gcd : y;
x = x == 0 ? b / gcd : x;
if(x == -1){
printf("0\n");
continue;
}
int ans = (c * 1.0 - b * y * 1.0 - a * x * 1.0) / (a * t * 1.0) + 1;
printf("%d\n", ans);
}
return 0;
}