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;
}