HDU 3240 Counting Binary Trees 数论-卡特兰数

题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=3240



卡特兰数递推公式h(i)=h(i-1)*(4*i-2)/(i+1)

如果直接算每一步,然后modm的话,有错误,因为h(i-1)%m后,h(i-1)*(4*i-2)不一定能整除(i+1),所以不行。
其实只需要把答案看做两部分的乘积:一部分是与m互素的,这一部分的乘法直接计算,除法改成乘逆元就行了;另一部分是若干个m的素因子的乘积,因为m<1,000,000,000,所以m的不同素因子不会太多,用一个数组记录每一个素因子的数量就行。这一部分的乘法就是把记录的素因子数量相加,除法就是把记录的素因子数量相减。最后计算这两部分的乘积对m的取模,也就是h(n)%m。


代码如下:

 

#include <iostream>

#include <vector>

#include <list>

#include <deque>

#include <queue>

#include <iterator>

#include <stack>

#include <map>

#include <set>

#include <algorithm>

#include <cctype>

#include <cstdio>

#include <cstdlib>

#include <cstring>

#include <string>

#include <cmath>

using namespace std;



const int N=10001;

typedef long long LL;



int su[N],num[N];

int n,m,sui;



void mul(LL &res,int k)

{

    for(int i=0;i<sui;i++)

    {

        while(k%su[i]==0)

        {

            k/=su[i];

            num[i]++;

        }

    }

    res=(res*k)%m;

}



int ext_gcd(int a,int b,int &x,int &y)

{

    int t,ret;

    if(!b)

    {

        x=1;y=0;return a;

    }

    ret=ext_gcd(b,a%b,y,x);

    y-=x*(a/b);

    return ret;

}



void chu(LL &res,int k)

{

    for(int i=0;i<sui;i++)

    {

        while(k%su[i]==0&&num[i]>0)

        {

            k/=su[i];

            num[i]--;

        }

    }

    if(k!=1)

    {

        int x,y,temp;

        temp=ext_gcd(k,m,x,y);

        x=(x%m+m)%m;

        res=(res*x)%m;

    }

}



int main()

{

    int i,j,k,t;

    while(scanf("%d%d",&n,&m)&&(n+m))

    {

        sui=0,t=m;

        for(i=2;i*i<=t;i++)

            if(t%i==0)

            {

                su[sui++]=i;

                while(t%i==0)

                    t/=i;

            }

        if(t>1)

            su[sui++]=t;

        memset(num,0,sizeof(num));

        LL res=1,sum=1,l;

        for(i=2;i<=n;i++)

        {

            mul(res,4*i-2);

            chu(res,i+1);

            l=res;

            for(j=0;j<sui;j++)

                for(k=0;k<num[j];k++)

                    l=l*su[j]%m;

            sum=(sum+l)%m;

        }

        printf("%lld\n",sum);

    }

    return 0;

}


 

 

你可能感兴趣的:(binary)