您的位置:首页 > 其它

51Nod-集合计数(拓展欧几里得+中国剩余定理)

2016-11-08 17:28 375 查看


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






System Message (题目提供者)

题目考点很容易看出,就是求解ax+by=n+1中解的个数

这里不能完全明白的地方是为什么除以LCM便是剩下可能的情况(巨巨们说是中国剩余定理)

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<limits.h>
#include<string>
#include<queue>
#include<vector>
#include<stack>
#include<math.h>
#include<map>
#include<algorithm>
using namespace std;
typedef long long ll;
#define maxn 1000005
#define Mod 1000000007
const int inf=1e10;
ll gcd(ll x,ll y)
{
if(y==0)return x;
return gcd(y,x%y);
}
void ex_gcd(ll a,ll b,ll &x,ll &y)
{
if(b==0)
{
x=1;
y=0;
return;
}
ll x1,y1;
ex_gcd(b,a%b,x1,y1);
x=y1;
y=x1-a/b*y1;
}
int  main()
{
ll n,a,b,i,j,T;
scanf("%lld",&T);
while(T--)
{
ll x,y;
scanf("%lld%lld%lld",&n,&a,&b);
n++;
ll temp=gcd(a,b),LCM=a/temp*b;
if(n%temp)
{
printf("0\n");
continue;
}
ll dn=n/temp;
ll da=a/temp;
ll db=b/temp;
ex_gcd(da,db,x,y);
x*=dn;
x=(x%db+db)%db;//求最小的非负x的解
if(x==0)
x+=db;//保证x是整数
ll ans=n-1-x*a;
//printf("%lld",a);
if(ans<0)printf("0\n");
else  printf("%lld\n",1+ans/LCM);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: