0x36 组合计数
组合计算的性质:
C(n,m)= m! / (n!(m-n)!)
C(n,m)=C(m-n,m); C(n,m)=C(n,m-1)+C(n-1,m-1);
二项式定理:(a+b)^n=sigema(k=0~n) C(k,n)*a^k*b^(n-k)
lucas定理:C(n,m)≡C(n%p,m%p)*C(n/p,m/p) (mod p)
catalan数: Cat(n)=C(n,2n)/n+1 Cat(n)=Cat(n-1)*(4n-2)/(n+1)
计算系数 通过二项式定理变形其实就是求C(n,k)*a^n*b^m,用下逆元
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; const LL mod=10007; LL quick_pow(LL A,LL p) { int ret=1; while(p!=0) { if(p%2==1)ret=(ret*A)%mod; A=(A*A)%mod;p/=2; } return ret; } LL jiecheng(LL k) { LL ret=1; for(int i=1;i<=k;i++)ret=(ret*i)%mod; return ret; } LL getniyuan(LL k) { return quick_pow(k,mod-2); } int main() { LL a,b,k,n,m; scanf("%lld%lld%lld%lld%lld",&a,&b,&k,&n,&m); LL ans=( (jiecheng(k)*getniyuan( jiecheng(n)*jiecheng(k-n)%mod )%mod) * (quick_pow(a,n)*quick_pow(b,m)%mod) )%mod; printf("%lld\n",ans); return 0; }
Counting Swaps 神仙题,%lyd吧。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; const LL mod=1e9+9; LL quick_pow(LL A,LL p) { int ret=1; while(p!=0) { if(p%2==1)ret=(ret*A)%mod; A=(A*A)%mod;p/=2; } return ret; } LL jiecheng(LL k) { LL ret=1; for(int i=1;i<=k;i++)ret=(ret*i)%mod; return ret; } LL getniyuan(LL k) { return quick_pow(k,mod-2); } int nxt[110000]; bool v[110000]; LL dfs(int x,int d) { if(v[x]==true)return d; v[x]=true; dfs(nxt[x],d+1); } int main() { int T; scanf("%d",&T); while(T--) { int n; scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&nxt[i]); LL tot=0,ans=1,cnt;cnt=n; memset(v,false,sizeof(v)); for(int i=1;i<=n;i++) { if(v[i]==false) { int L=dfs(i,0); if(L>1) { tot++; ans=(ans*quick_pow(L,L-2)%mod)*getniyuan(jiecheng(L-1))%mod; } else cnt--; } } if(tot==0)printf("1\n"); else { ans=ans*jiecheng(cnt-tot)%mod; printf("%lld\n",ans); } } return 0; }
bzoj1951 由欧拉定理的推论,变成计算sigema(d|n)C(d,n)%(mod-1),这个用卢卡斯定理搞,但是mod不是质数,那么分解分别搞,然后得到4个同余方程,解出就是指数了,最后快速幂即可。
upd:感觉之前的阶乘模数有点假。。但是应该是对的
快速幂+crt并没有exgcd优秀的说。。。卡了一波常数才过的。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; const LL mod=999911659; const LL md[]={2,3,4679,35617}; int quick_pow(int A,int p,int mod) { int ret=1; while(p!=0) { if(p%2==1)ret=(LL)ret*A%mod; A=(LL)A*A%mod;p/=2; } return ret; } LL fac[4][41000],fac_inv[4][41000]; void initC() { for(int j=0;j<=3;j++)fac[j][0]=1,fac_inv[j][0]=1; for(int i=1;i<=md[3];i++) for(int j=0;j<=3;j++) fac[j][i]=fac[j][i-1]*i%md[j],fac_inv[j][i]=quick_pow(fac[j][i],md[j]-2,md[j]); } LL getC(LL n,LL m,LL p){return fac[p][n]*fac_inv[p][m]%md[p]*fac_inv[p][n-m]%md[p];} LL lucas(LL n,LL m,LL p) { LL ans=1; while(m>0) { LL a=n%md[p],b=m%md[p]; if(a<b)return 0; ans=ans*getC(a,b,p)%md[p]; n/=md[p],m/=md[p]; } return ans; } LL a[4]; LL solve(LL n,LL k) { for(int i=0;i<=3;i++)a[i]=lucas(n,k,i); LL M=mod-1,x=0; for(int i=0;i<=3;i++)//crt x=(x+a[i]*(M/md[i])*quick_pow(M/md[i],md[i]-2,md[i]))%(mod-1); return x; } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); initC(); int n,G,p=0; scanf("%d%d",&n,&G); if(G==mod){printf("0\n");return 0;} for(int i=1;i*i<=n;i++) if(n%i==0) { p=(p+solve(n,i))%(mod-1); if(i*i!=n)p=(p+solve(n,n/i))%(mod-1); } printf("%d\n",quick_pow(G,p,mod)); return 0; }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; const LL mod=999911659; const LL md[4]={2,3,4679,35617}; LL exgcd(LL a,LL b,LL &x,LL &y) { if(a==0) { x=0;y=1; return b; } else { LL tx,ty; LL d=exgcd(b%a,a,tx,ty); x=ty-b/a*tx; y=tx; return d; } } LL quick_pow(LL A,LL p) { LL ret=1; while(p!=0) { if(p%2==1)ret=(ret*A)%mod; A=(A*A)%mod;p/=2; } return ret; } LL inv(LL a,LL p) { LL x,y; LL d=exgcd(a,p,x,y); return (x%p+p)%p; } //--------------------------------------------------- LL jc[110000]; LL lucas(LL N,LL M,LL p) { LL ans=1; while(M>0) { LL a=N%p,b=M%p; if(a>b)return 0; ans=ans*jc[b]%p; ans=ans*inv(jc[a],p)%p; ans=ans*inv(jc[b-a],p)%p; N/=p;M/=p; } return ans; }//lucas LL g[110000]; void getzs(LL n) { jc[0]=1; for(int i=1;i<=md[3];i++)jc[i]=(jc[i-1]*i)%(mod-1); for(int i=1;i*i<=n;i++) { if(n%i==0) { for(int j=0;j<=3;j++) g[j]=(g[j]+lucas(i,n,md[j]))%md[j]; if(i!=n/i) { for(int j=0;j<=3;j++) g[j]=(g[j]+lucas(n/i,n,md[j]))%md[j]; } } } } //--------------------------------------------------- LL u1,v1,u2,v2; void merge() { LL A=u1,B=u2,K=v2-v1,x,y; LL d=exgcd(A,B,x,y); x=(x*(K/d)%(B/d)+(B/d))%(B/d); v1=u1*x+v1; u1=u1/d*u2; } LL solve() { u1=md[0],v1=g[0]; for(int i=1;i<=3;i++) u2=md[i], v2=g[i], merge(); return v1; } int main() { LL n,g; scanf("%lld%lld",&n,&g);g%=mod; if(g==0){printf("0\n");return 0;} getzs(n); LL p=solve(); printf("%lld\n",quick_pow(g,p)); return 0; }
pain and happy in the cruel world.