51nod 1352 扩展欧几里德

时间:2023-03-08 17:13:48

给出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,y),并且 x = k1 * A , y = k2 * B;(k1,k2为正整数) ,并且x + y = n + 1;
得到不定方程k1*A + k2*B = n+1。 根据扩展欧几里德算法得到一组解,计算满足条件的有多少组即可。
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define INF 1000000001
#define ll __int64
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int MAXN = ;
ll A,B,n;
int gcd(int a,int b)
{
return b > ? gcd(b,a%b):a;
}
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(b == ){
x = ;
y = ;
return a;
}
ll r = exgcd(b,a%b,x,y);
ll t = x;
x = y;
y = t - (a/b) * y;
return r;
}
ll getnum(ll x,ll k)
{
double l = -(x * 1.0)/k;
if(l <= ){
return (ll)l;
}
if(x % k){
return -x/k + ;
}
return x/k;
}
ll getnum1(ll n,ll B,ll y,ll k)
{
ll t = (y - n / B) / k;
if(B*(y - k * t) > n){
t ++;
}
return t;
}
int main()
{
int t;
ll ans, x, y;
cin >>t;
while(t--){ cin >>n >>A >>B;
ans = ;
int ret = exgcd(A,B,x,y);
if((n+) % ret != ){
ans = ;
}
else {
ll rt = (n+) / ret;
x *= rt;
y *= rt;
ll k1 = B / ret;
ll k2 = A / ret; //cout<<x<<' '<<y<<endl;
ll f,b;
ll c_x = getnum(x,k1);
ll c_y = getnum1(n,B,y,k2);
f = max(c_x,c_y);
ll fp1 = (n / A - x)/k1;
if(A*(x+k1*fp1) > n) fp1 --;
ll fp2 = y / k2;
b = min(fp2,fp1);
ans = (b - f + );
}
cout<<(ans > ? ans : )<<endl;
}
}