51nod_1352_集合计数 (exgcd)

Posted gsimt

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51nod_1352_集合计数 (exgcd)相关的知识,希望对你有一定的参考价值。

题意:ax+by=n+1,x>0,y>0的解的个数

先判断(a,b)是否整除n+1,不整除无解,有解后用exgcd算出一解(x1,y1),

然后在草稿纸上写下x1+d*(b/gcd(a,b))>0,  y1-d*(b/gcd(a,b))>0,算出d的范围,大于号一侧向下取整(若本身为整数,还要-1,因为取不到等号),小于相反。

注意 : 负数时,取整是变大,正数是变小。

#include<algorithm>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<cstdlib>
#define getrand(a,b) (int)((rand()/33000.0)*((b)-(a)+1))+(a)
using namespace std;
typedef long long LL;
const int maxnn=100+5;
const int maxn=100000+5;
const int mod=1e9+7;
int gcd(LL a,LL b){
    if(b==0)return (int)a;
    else return gcd(b,a%b);
}
void exgcd(LL a,LL b,LL& x,LL& y,LL g){
    if(a==g){
        x=1;
        y=0;
        return;
    }
    exgcd(b,a%b,y,x,g);
    y-=(a/b)*x;
} 
int main()
{
    LL t,n,a,b,g,x,y,k,d1,d2;
    cin>>t;
    while(t--){
        cin>>n>>a>>b;
        g=gcd(a,b);
        if((n+1)%g){
            cout<<0<<endl;
            continue;
        } 
        if(a<b) swap(a,b);
        exgcd(a,b,x,y,g);
        k=(n+1)/g;
        x*=k;y*=k;
        if(a*x+b*y==0)cout<<0<<endl;
        else if(a*x+b*y>0){
            d1=(-x*g)/b;
            if(-x*g==d1*b||-x*g>=0)d1++;
            d2=(y*g)/a;
            if(a*d2==y*g||y*g<=0)d2--;
            cout<<d2-d1+1<<endl;
        }
        else{
            d2=(-x*g)/b;
            if(b*d2==-x*g||-x*g<=0)d2--;
            d1=(y*g)/a;
            if(d1*a==y*g||y*g>=0)d1++;
            cout<<d2-d1+1<<endl;
        }    
    }

    return 0;
}

 

以上是关于51nod_1352_集合计数 (exgcd)的主要内容,如果未能解决你的问题,请参考以下文章

51nod 1352 集合计数 扩展欧几里得

51nod 1352 集合计数

51Nod 1352 集合计数 扩展欧几里得

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

扩展欧几里德解的数量(51nod 1352)

51Nod1222 最小公倍数计数 数论 Min_25 筛