zoukankan      html  css  js  c++  java
  • [HDU3240]Counting Binary Trees(不互质同余除法)

    Counting Binary Trees

    Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 564    Accepted Submission(s): 184

    Problem Description
    There are 5 distinct binary trees of 3 nodes:

    Let T(n) be the number of distinct non-empty binary trees of no more than n nodes, your task is to calculate T(n) mod m.
     
    Input
    The input contains at most 10 test cases. Each case contains two integers n and m (1 <= n <= 100,000, 1 <= m <= 109) on a single line. The input ends with n = m = 0.
     
    Output
    For each test case, print T(n) mod m.
     
    Sample Input
    3 100 4 10 0 0
    Sample Output
    8 2
    Source

    题意:求Catalan数的前n项和。

    直接递推公式就好了,但是有一个问题,递推式里有除法,而由于除数与模数不互质,不能预处理逆元,这里有一个求不互质同余除法的方法(前提是结果必须是整数,所以只能用来求Catalan,Stirling和组合数这样的数)

    $frac{a}{b}equiv c (mod   d)$,我们先将d质因数分解,然后对于$a$和$b$将d的质因子部分单独统计,剩余部分直接exgcd求逆元即可。

    因为剩余部分满足互质所以可以直接做逆元,而我们有$pequiv p(mod ap)$,所以最后质因子部分直接乘就可以了。

    这样就解决了HNOI2017的70分做法。

    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<algorithm>
    #define rep(i,l,r) for (int i=l; i<=r; i++)
    using namespace std;
    
    const int maxn=100010;
    typedef long long ll;
    
    ll ans,cnt[maxn];
    vector<int> prime;
    int n,m;
    
    void exgcd(ll a,ll b,ll &x,ll &y){
        if (!b) x=1,y=0;
        else exgcd(b,a%b,y,x),y-=x*(a/b);
    }
    
    ll inv(ll a,ll p){ ll x,y; exgcd(a,p,x,y); return (x+p)%p; }
    
    void getPrime(){
        ll t=m;
        for (int i=2; i*i<=t; i++)
            if (t%i==0){
                prime.push_back(i);
                while (t%i==0) t/=i;
            }
        if (t>1) prime.push_back(t);
    }
    
    void solve(){
        getPrime(); ans=1; ll res=1;
        rep(i,2,n){
            ll fz=4*i-2,fm=i+1;
            for (int k=0; k<(int)prime.size(); k++)
                if (fz%prime[k]==0)
                    while (fz%prime[k]==0) fz/=prime[k],cnt[k]++;
            res=(res*fz)%m;
            for (int k=0; k<(int)prime.size(); k++){
                if (fm%prime[k]==0)
                    while (fm%prime[k]==0) fm/=prime[k],cnt[k]--;
            }
            if (fm>1) res=(res*inv(fm,m))%m;
            ll t=res;
            for (int k=0; k<(int)prime.size(); k++)
                rep(s,1,cnt[k]) t=(t*prime[k])%m;
            ans=(ans+t)%m;
        }
        printf("%lld
    ",ans);
    }
    
    int main(){
        while(~scanf("%d%d",&n,&m) && n+m)
            prime.clear(),memset(cnt,0,sizeof(cnt)),solve();
        return 0;
    }
    
  • 相关阅读:
    页面get请求 中文参数方法乱码问题
    java版ftp简易客户端(可以获取文件的名称及文件大小)
    文件下载
    kafka:一个分布式消息系统
    Executor的线程代码
    验证码的生成
    二维码的简单实现
    rsync实现大致流程描述
    C++中模板生成时机
    gcc虚函数表生成时机
  • 原文地址:https://www.cnblogs.com/HocRiser/p/8628987.html
Copyright © 2011-2022 走看看