zoukankan      html  css  js  c++  java
  • 【数论】求解ax+by=c x,y为非负数的解的个数 以及 lucas定理

    Comet OJ - 模拟赛 #2 Day1 小猪佩奇跳格子

    求解ax+by=n x,y为非负数的解的个数 ,答案对10007取模

    (然后这道题x个a和y个b的顺序不同,算作不同)

    然后数据范围:a,b,n<=10^9 。

    当场翻了数论书,有这几个点:

    1,对于二元一次不定方程ax+by=c,有整数解的充要条件是 (a,b)|c。

    2,若(a,b)=1,且不定方程有整数解x=x0,y=y0,则它的一切整数解可表示成:

      x=x0+bt; y=y0-at;  (t为任意整数)

    3,可以用exgcd 求 ax+by=gcd(a,b) 得到x0 y0,所以ax+by=c 的解x0=x0/gcd(a,b)*c  y0=y0/gcd(a,b)*c;

    所以做法是先判断有没有解,然后有的话 就除去它们的公因数,然后由xy的非负性判断t的范围

    然后因为这道题x个a和y个b的顺序不同,算作不同,然后就是组合数了,然后因为是小模,所以是lucas定理。。。

    (我居然现场翻书学的lucas,大一学的然后忘了。。可怕QAQ

    #include<bits/stdc++.h>
    #define debug1 printf("!");
    #define debug2 puts("#");
    
    using namespace std;
    typedef long long ll;
    const int mod=1e4+7;
    const int maxn=1e7+50;
    const int inf=0x3f3f3f3f;
    
    ll jc[mod+50];
    ll kpow(ll a,ll b)
    {
        a%=mod;
        ll ans=1;
        while(b)
        {
            if(b&1)ans=ans*a%mod;
            a=a*a%mod;
            b>>=1;
        }
        return ans;
    }
    ll C(ll n,ll m){
        if(m>n)return 0;
        return ((jc[n]*kpow(jc[m],mod-2))%mod*kpow(jc[n-m],mod-2)%mod);
    }
    ll Lucas(ll n,ll m){
        if(!m)return 1;
        return C(n%mod,m%mod)*Lucas(n/mod,m/mod)%mod;
    }
    inline void init()
    {
        jc[0]=1;
        for(int i=1;i<=mod;i++)
        {
            jc[i]=(jc[i-1]*i)%mod;
        }
    }
    
    inline ll exgcd(ll a,ll b,ll &x,ll &y)
    {
        if(!b){
            x=1;y=0;
            return a;
        }
        ll g=exgcd(b,a%b,x,y);
        ll t=x;
        x=y;
        y=t-a/b*y;
        return g;
    }
    
    int main()
    {
        init();
        ll n,a,b,d;
        scanf("%lld%lld%lld",&n,&a,&b);
        if(a>b)swap(a,b);
        d=__gcd(a,b);
        if(n%d!=0)
        {
            puts("0");return 0;
        }
        n/=d;a/=d;b/=d;
    
        ll x0,y0,x,y;
        exgcd(a,b,x0,y0);
        x0*=n;y0*=n;
        ll up=y0/a,down=-x0/b;
        ll ans=0;
        for(int t=down;t<=up;t++)
        {
            x=x0+b*t;y=y0-a*t;
            if(t<0&&x<0)break;
            if(t>0&&y<0)break;
            if(x<0||y<0||x>n||y>n)continue;
            ans=(ans+Lucas(x+y,min(x,y)))%mod;
        }
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    9、 vector与list的区别与应用?怎么找某vector或者list的倒数第二个元素
    8、STL的两级空间配置器
    hdoj--1342--Lotto(dfs)
    FZU--2188--过河(bfs暴力条件判断)
    zzuli--1812--sort(模拟水题)
    hdoj--3123--GCC(技巧阶乘取余)
    zzulioj--1089--make pair(dfs+模拟)
    zzulioj--1815--easy problem(暴力加技巧)
    zzulioj--1801--xue姐的小动物(水题)
    HIToj--1076--Ordered Fractions(水题)
  • 原文地址:https://www.cnblogs.com/kkkek/p/11969080.html
Copyright © 2011-2022 走看看