51nod 1352 扩展欧几里德
给出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 = 50010; ll A,B,n; int gcd(int a,int b) { return b > 0 ? gcd(b,a%b):a; } ll exgcd(ll a,ll b,ll &x,ll &y) { if(b == 0){ x = 1; y = 0; 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 <= 0){ return (ll)l; } if(x % k){ return -x/k + 1; } 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 = 0; int ret = exgcd(A,B,x,y); if((n+1) % ret != 0){ ans = 0; } else { ll rt = (n+1) / 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 + 1); } cout<<(ans > 0 ? ans : 0)<<endl; } }