1352 集合计数(求解的个数)

1352 集合计数 基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题 收藏 关注 给出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

题解:用扩展欧几里得的公式求解的个数,首先要求出一个最小解,然后找到a和b 的最小公倍数,然后一个莫名其妙的原理就可以解出来了

#include <cstdio> #include <cstring> #include <math.h> #include <algorithm> using namespace std; #define LL long long #define MOD 1000000007 #define M 200010 #define INF 0x3f3f3f3f LL n; LL exgcd(LL a, LL b, LL &d, LL &x, LL &y) { if(!b) { d = a; x = 1; y = 0; } else { exgcd(b, a%b, d, y, x); y -= x * (a / b); } } int main() { int t; LL x, y, k, d, a, b, bl, xm, ym, al, num; scanf("%d", &t); while(t--) { scanf("%lld%lld%lld", &n, &a, &b); exgcd(a, b, d, x, y); n++; k = n / d; if(n % d != 0) { PRintf("0\n"); continue; } else { bl = b / d, al = a / d; xm = (x*k%bl + bl) % bl; LL lc = a * b / d;//最小公倍数 if(xm == 0) { xm = bl;//最小的正数解 } num = 0; LL remain = n - 1 - xm * a;//求出余下的值,这里注意n 要减去 1,或许因为已经有了一组解 if(remain >= 0)//因为n减去了1,所以余下的值等于0的话也无所谓 { num = 1; num += remain / lc;//余下的值除以最小公倍数 } } printf("%lld\n", num); } return 0; }