关于组合数的一些东西

来源:互联网 发布:网络电视怎么连接手机 编辑:程序博客网 时间:2024/04/29 00:47

组合数对应着杨辉三角杨辉三角中第i行j个表示Cj1i1

由组合数的定义

Cji=Ciji

根据二项式展开(x+1)n=ni=0Cinxi

x=1ni=0Cin=2n

2|i,inCin=2/|n,inCin=2

这个可以在杨辉三角上将每一个点分解得出:
2|n,由于有对称性,证明显然
2/|n,如图
explanation1

di=0Cin+i=Cdn+d+1

同样,将杨辉三角上的点合并:
explanation2

Caa+b+cCbb+c=Caa+bCca+b+c

=(a+b+c)!a!(b+c)!(b+c)!b!c!=(a+b+c)!a!b!c!=(a+b)!a!b!(a+b+c)!(a+b)!c!=Cca+b+cCaa+b

也可以用定义证明。

然后是一道题

【51nod 1362】推箱子

大意:

n*m的网格图从格点(0,0)走到第n行的某个格子停止,要求只能向下或向右,或到右下方的格子
即(x,y)走到(x+1,y),(x,y+1),(x+1,y+1)

问方案数,对X取模
1n800,1m,X2109
多组数据

Input

1 2 103 3 100

Output

996

n这么小?!

枚举终点
再枚举斜着走i格,然后套上组合数:

Ans=p=0mi=0min(p,n)Cin+piCnini+pi  (ni)+(pi)+i=n+pi=p=0mi=0min(p,n)CinCpin+pi=i=0min(n,m)Cinp=imCnn+pi=i=0min(n,m)Cinp=0miCnn+p ppi=i=0min(n,m)CniCn+1n+mi+1

%X怎么办?

X不是质数!!

X不是质数就不能用费马小定理求逆元。

欧拉定理求逆元呢?
那要互质啊。

诶n<=800!

那我们直接强行分解质因数就好了!!
然而质因数个数?

想到由于x的质因数很小,所以,与x互质的分母直接用欧拉定理求逆元。其他的强算即可。

记得要用快速乘,不然unsignedll都会爆。

code:

#include<cstdio>#include<cctype>#define ll long longusing namespace std;int pr[100100],s[100100],d[100100],n,m,t,ola,c[1000][1000];ll x,ans,Ans,div;bool bz[100100];void swap(int &a,int &b){a^=b,b^=a,a^=b;}ll qmul(ll a,ll b){    b%=x;a%=x;    ll r=0;for(;b;b>>=1,a=(a+a)%x)if(b&1)r=(r+a)%x;return r;}ll qpow(ll a,int b){    a%=x;    ll r=1;for(;b;b>>=1,a=qmul(a,a))if(b&1)r=qmul(r,a);return r;}void inc(int x){    for(int n,i=1;i<=t;i++)if(x%d[i]==0){        n=0;do n++,x/=d[i];while(x%d[i]==0);        s[i]+=n;    }ans=qmul(ans,(ll)x);}void dec(int x){    for(int n,i=1;i<=t;i++)if(x%d[i]==0){        n=0;do n++,x/=d[i];while(x%d[i]==0);        s[i]-=n;    }div=qmul(div,(ll)x);}int main(){    for(int i=2;i<100000;i++){        if(!bz[i])pr[++pr[0]]=i;        for(int j=1;j<=pr[0] && i*pr[j]<100000;j++){            bz[i*pr[j]]=1;if(i%pr[j]==0)break;        }    }    while(~scanf("%d %d %lld",&n,&m,&x)){        t=0;Ans=0;ola=1;        for(int i=1,tmp=x;i<=pr[0] && tmp!=1;i++){            if(tmp%pr[i]==0){                d[++t]=pr[i];tmp/=pr[i];ola=ola*(pr[i]-1);                while(tmp%pr[i]==0)tmp/=pr[i],ola=ola*pr[i];            }            if(tmp==1)break;            if(pr[i]*pr[i]>tmp){d[++t]=tmp;ola=ola*(tmp-1);break;}        }        for(int i=0;i<=n && i<=m;i++){            ans=1;div=1;            for(int j=1;j<=t;j++)s[j]=0;            for(int j=0;j<i;j++)inc(n-j),dec(j+1);            for(int j=0;j<=n;j++)inc(n+m-i+1-j),dec(j+1);            for(int j=1;j<=t;j++)ans=qmul(ans,qpow((ll)d[j],s[j]));            Ans=(Ans+qmul(ans,qpow(div,ola-1)))%x;        }printf("%lld\n",Ans);    }}
原创粉丝点击