51nod 集合计数(拓展欧几里得)

来源:互联网 发布:it猎头 编辑:程序博客网 时间:2024/05/21 09:28

()

给出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个。Input1行:1个整数T(1<=T<=50000),表示有多少组测试数据。第2 - T+1行:每行三个整数N,A,B(1<=N,A,B<=2147483647)Output对于每组测试数据输出一个数表示满足条件的集合的数量,占一行。Input示例25 2 410 2 3Output示例12
这道题的意思就是求:i=A*x;N+1-i=B*y;其实他就A*x+B*y=i+N+1-i->A*x+B*y=N+1即Ax≡1+N(mod B)这样子我们可以用拓展欧几里得求出gcd和x。判断如果gcd(A,B)|(1+N)(整除)的话,那就就是有解,否则的话就是无解,直接输出0.之后呢,我们要求出最小的非负整数x1,具体怎么求,之前有写过。(对应B的系数为y1)x1就是一个符合的集合数,接着(N-A*x1)/LCM(A,B)即可算出剩下的集合数量。(这里应该很容易理解吧,如样例2,lcm为6,那么每次转移都是(A*x1+6*n)+(B*y1-6*n)=N+1)(n=1,2....(n的取值应该在有效范围))ps:令A,B的最小公倍数为lcm,方程在lcm范围内的最小非负整数解是a,则有a+lcm*x<=n,若a!=0那么x即为所求的解得个数 否则x-1即为所求.
#include<iostream>#include<cstring>#include<cstdlib>#include<algorithm>#include<cctype>#include<cmath>#include<ctime>#include<string>#include<stack>#include<deque>#include<queue>#include<list>#include<set>#include<map>#include<cstdio>#include<limits.h>#define fir first#define sec second#define fin freopen("/home/ostreambaba/文档/input.txt", "r", stdin)#define fout freopen("/home/ostreambaba/文档/output.txt", "w", stdout)#define mes(x, m) memset(x, m, sizeof(x))#define pii pair<int, int>#define Pll pair<ll, ll>#define INF 1e9+7#define Pi 4.0*atan(1.0)#define MOD 1000000007#define lowbit(x) (x&(-x))#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define ls rt<<1#define rs rt<<1|1typedef long long ll;typedef unsigned long long ull;const double eps = 1e-12;const int maxn = 1010;using namespace std;inline int read(){    int x(0),f(1);    char ch=getchar();    while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();    return x*f;}inline int extend_gcd(ll a, ll b, ll &x, ll &y){    if(0==b){        x=1;        y=0;        return a;    }else{        ll d=extend_gcd(b,a%b,x,y);        ll tmp=x;        x=y;        y=tmp-a/b*x;        return d;    }}int main(){   // fin;    ll N, A, B, x, y, d, q;    int T;    T=read();    while(T--){        scanf("%lld%lld%lld",&N,&A,&B);        d=extend_gcd(A,B,x,y); //gcd        q=A/d*B; //LCM        if((1+N)%d){            printf("0\n");            continue;        }        else{            int count=0;            ll mod=B/d;            ll min=((1+N)/d*x%mod+mod)%mod; //最小非负整数            if(min==0){ //会出现0的情况,集合是[1,N]的,所欲这里需要讨论                min=mod;            }            int res=N-A*min;            if(res<0){                   printf("0\n");                continue;            }            else{                count=res/q+1;//+1是min是第一个符合的集合(在范围内[1,N])            }            printf("%d\n",count);        }    }}
0 0
原创粉丝点击