zoukankan      html  css  js  c++  java
  • 51nod1352 集合计数(扩展欧几里得)

    题目链接:http://www.51nod.com/Challenge/Problem.html#!#problemId=1352


    思路:题目就是求ax+by=n+1,有几个符合的(x,y)。

    首先找到a,b的最大公约数d,n+1是d的倍数才有符合的解。
    我们可以简单证明下:因为d是a,b的最大公约数,设a=k1*d,b=k2*d(k1,k2为正整数).
    所以a*(k1*d)+b*(k2*d)=n+1,即(n+1)/d=a*k1+b*k2,所以n+1一定要是最大公约数的倍数才有解

     先用算出a*x+b*y=n+1 的最小正数x解,如果此时y不是正数则没有解答案是0,如果是正数则答案是y/(a/gcd(a,b))(+1)

    (如果y是a/gcd(a,b)的倍数不加1,不是就加1,可以这样理解y本身是一个解,如果整除,y的解包含进去了,不整除,y这个解没加)

     也可以上下同时乘以b,   写成b*y/(a*b/gcd(a,b))又因为a*b/gcd(a,b)就是a,b的最小公倍数,所以又可以写成b*y/lcm(a,b)(+1)(lcm(a,b)的最小公倍数)

     

    为什么答案是y/(a/gcd(a,b)(+1)呢?

     因为(x,y)是一组解,则(x+k*b/gcd(a,b),y-k*a/gcd(a,b))(k为正整数)也是解。自己可以动手写就知道了

     为什么是除以a/gcd(a,b)不是除以a呢?因为是除a解多还是除a/gcd(a,b)多?我也想了半天才知道。。。。笑笑自己弱鸡

     

    哪最小正数解x怎么算呢?

     我们只要用扩展欧几里得模板算出a*x+b*y=gcd(a,b) 的一个解x 再乘以(n+1)/gcd(a,b)就可以了得出a*x+b*y=n+1的一个x解,

     但是此时x有可能不是最小,也有可能是负数,怎么办?

     由上面我们可以知道a*(x+b/gcd(a,b))+b*(y-a/gcd(a,b))=n+1 每b/gcd(a,b)有一个x解,只要x对b/gcd(a,b)取模就行了,

     再判断是负数就加b/gcd(a,b)就是最小正数解了。

    代码:
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    ll exgcd(ll a,ll b,ll &x,ll &y)
    {
        if(b==0)
        {
            x=1;
            y=0;
            return a;
        }
        ll ans=exgcd(b,a%b,x,y);
        ll t=x; 
        x=y; 
        y=t-(a/b)*y;
        return ans;
    }
    
    int main()
    {
        ll t;
        cin>>t;
        ll n,a,b;
        while(t--)
        {
            cin>>n>>a>>b;
            ll x,y;
            ll d=exgcd(a,b,x,y);//a,b的最大公约数
            //cout<<x<<" "<<y<<endl; 
            ll lcm=a*b/d;
            if((n+1)%d)
                cout<<"0"<<endl;
            else
            {
                x=x*(1+n)/d;
                ll r=b/d;
                x=x%r;
                while(x<=0) 
                    x+=r;//最小的正整数解x 
                ll s=n+1-x*a;//s为b*y 
                if(s<0)
                    cout<<"0"<<endl;
                else
                {
                    if(s%a)
                        cout<<1+s/lcm<<endl;
                    else
                        cout<<s/lcm<<endl;
                }
            }
        }
    }
    
    
    
     
  • 相关阅读:
    ThinkPHP3.2 整合支付宝RSA加密方式
    代码风格规范
    Mac下安装composer
    MAC 下安装RabbitMQ
    Redis配置
    git 分支
    PHP常用数组操作方法汇总
    php 不用第三个变量 交换两个变量的值汇总
    PHP配置错误信息回报的等级
    Apache同一个IP上配置多域名
  • 原文地址:https://www.cnblogs.com/xiongtao/p/9366459.html
Copyright © 2011-2022 走看看