【组合数】ZOJ3557 HDU3944

来源:互联网 发布:顶级域名证书合法吗 编辑:程序博客网 时间:2024/06/05 09:04

大佬博客:

http://blog.csdn.net/acdreamers/article/details/8037918

/*ZOJ 3557题意:从n个数中取m个数并且这m个数字之间不能相邻思路:n-m个数不取,留下n-m+1个空将这m个数插入n-m+1个空中所以C(n-m+1,m)*/#include <bits/stdc++.h>using namespace std;typedef long long LL;LL quickpow(LL x,LL n,LL p){    LL ans=1;    while(n)    {        if(n&1)            ans=ans*x%p;        x=x*x%p;        n>>=1;    }    return ans;}LL C(LL n,LL m,LL p){    LL up=1,down=1;    for(int i=1;i<=m;i++)    {        up=up*(n-i+1)%p;        down=down*i%p;    }    return up*quickpow(down,p-2,p)%p;}LL Lucas(LL n,LL m,LL p){    if(m==0)        return 1;    return C(n%p,m%p,p)*Lucas(n/p,m/p,p)%p;}int main(){    LL n,m,p;    while(~scanf("%lld%lld%lld",&n,&m,&p))    {        printf("%lld\n",Lucas(n-m+1,m,p));    }    return 0;}

/*HDU 3944题意:给出一个杨辉三角,给出一个坐标(n,m)求(n,m)到(1,1)路径上数字的最小和思路:从(n,m)点一直向左上方走,走到边缘就一直往上走根据对称性n/2右边跟左边是一样的往上找的推的公式:主要是C(n-k,0)=C(n-k+1,0)将第一行的第一个式子替换了然后根据C(n,m)=C(n-1,m),C(n-1,m-1)不断合并c(n-k,0)+c(n-k+1,1)+c(n-k+2,2)+...+c(n-k+i,i)+...+c(n,k)+n-k=c(n-k+1,0)+c(n-k+1,1)+c(n-k+2,2)+...+c(n-k+i,i)+...+c(n,k)+n-k=c(n-k+2,1)+c(n-k+2,2)+...+c(n-k+i,i)+...+c(n,k)+n-k=c(n-k+3,2)+...+c(n-k+i,i)+...+c(n,k)+n-k=c(n-k+i,i-1)+...+c(n-k+i,i)+c(n,k)+n-k=c(n,k-1)+c(n,k)+n-k=c(n+1,k)+n-k预处理出对所有p的阶乘和逆元*/#include <bits/stdc++.h>using namespace std;typedef long long LL;const int MAXN=1e4;LL fac[MAXN+1][MAXN+1],inv[MAXN+1][MAXN+1];int prime[MAXN+1],rk[MAXN+1];void getPrime()//求素数{    memset(prime,0,sizeof(prime));    for(int i=2; i<=MAXN; i++)    {        if(!prime[i])        {            prime[++prime[0]]=i;            rk[i]=prime[0];        }        for(int j=1; j<=prime[0]&&prime[j]<=MAXN/i; j++)        {            prime[prime[j]*i]=1;            if(i%prime[j]==0)                break;        }    }}LL quickpow(LL x,LL n,LL p)//快速幂{    LL ans=1;    x%=p;    while(n)    {        if(n&1)            ans=ans*x%p;        x=x*x%p;        n>>=1;    }    return ans;}void Init()//预处理{    for(int i=1; i<=prime[0]; i++)    {        fac[i][0]=inv[i][0]=1;        for(int j=1; j<prime[i]; j++)        {            fac[i][j]=(fac[i][j-1]*j)%prime[i];            inv[i][j]=quickpow(fac[i][j],prime[i]-2,prime[i]);        }    }}LL C(LL n,LL m,LL p)//计算组合数{    if(m>n)        return 0;    else if(m==n)        return 1;    int index=rk[p];    return fac[index][n]*(inv[index][m]*inv[index][n-m]%p)%p;}LL Lucas(LL n,LL m,LL p){    if(m==0)        return 1;    return C(n%p,m%p,p)*Lucas(n/p,m/p,p)%p;}int main(){    int cas=0;    LL n,k,p;    getPrime();    Init();    while(~scanf("%lld%lld%lld",&n,&k,&p))    {        if(k>n/2)            k=n-k;        printf("Case #%d: %lld\n",++cas,(Lucas(n+1,k,p)+n-k)%p);    }    return 0;}


0 0
原创粉丝点击