组合数C
1.最早的思路
C如果用C(n,m)=n!/(m!(n-m)!),需要预处理阶乘,
这样的话,会TLE+MLE(自行脑补)。
2.暴力出奇迹
既然阶乘不行,那我们回归暴力
可以将阶乘枚举,然后分解质因数
再用高精度乘法一个个处理,
这样,就不需要什么除法了
3.原理呢?
还是这个式子:C(n,m)=n!/(m!(n-m)!)
显然,由于组合数为正整数,
所以所有的除数都会被抵消掉。
分解质因数后,就可以抵消除数,
那么我们就不需要除法了。
struct node { int len;short s[5005]; void wrt() { for(register int i=len-1;i>=0;i--) { printf("%ld",s[i]); }printf(" "); } }ans; node sum(node x,node y) { node s;s.len=max(x.len,y.len)+2; for(register int i=0;i<=max(x.len,y.len)+3;i++)s.s[i]=0; int last=0; for(register int i=0;i<max(x.len,y.len);i++) { s.s[i]=(x.s[i]+y.s[i]+last)%10; last=(x.s[i]+y.s[i]+last)/10; } if(last)s.s[max(x.len,y.len)]=last; s.len=max(x.len,y.len)+2; while(s.s[s.len]==0)s.len--; s.len++;return s; } node times(node x,node y) { node c; c.len=0; for(int i=0;i<=(x.len+y.len)+2;i++) { c.s[i]=0; } for(int i=0;i<x.len;i++) { int last=0; for(int j=0;j<y.len;j++) { c.s[i+j]=c.s[i+j]+last+x.s[i]*y.s[j]; last=c.s[i+j]/10; c.s[i+j]%=10; } c.s[i+y.len]+=last; } int lenc=(x.len+y.len)+2; while(c.s[lenc]==0)lenc--; lenc++;c.len=lenc; return c; } node make(int x) { node s;s.len=0; for(int i=1;i<=10;i++)s.s[i]=0; while(x) { s.s[s.len++]=x%10; x/=10; } return s; } node del(node x,node y) { node s; for(int i=0;i<max(x.len,y.len)+2;i++)s.s[i]=0; int last=0; for(int i=0;i<max(x.len,y.len);i++) { if(x.s[i]>=y.s[i]+last) { s.s[i]=x.s[i]-y.s[i]-last; last=0; } else { s.s[i]=10+x.s[i]-y.s[i]-last; last=1; } } s.len=max(x.len,y.len)+2; while(s.s[s.len]==0)s.len--; s.len++; return s; } bool check(node x,node y) { if(x.len>y.len)return 1; if(x.len<y.len)return 0; bool bz=0; for(int i=x.len-1;i>=0;i--) { if(x.s[i]>y.s[i]){bz=1;break;} if(x.s[i]<y.s[i]){bz=0;break;} } return bz; } void solve(int x,int k) { while(x>1) { num[to[x]]+=k; x/=to[x]; } } node C(int m,int n) { x.len=0;for(int i=1;i<=5000;i++)x.s[i]=0; node s;s.len=1;s.s[0]=1; for(int i=1;i<=10000;i++)num[i]=0; for(int i=n-m+1;i<=n;i++)solve(i,1); for(int i=1;i<=m;i++)solve(i,-1); for(int i=1;i<=10000;i++) { node ber=make(i); for(int j=1;j<=num[i];j++) { s=times(s,ber); } } return s; } void pre() { for(int i=2;i<=10000;i++) { if(!to[i]) { to[i]=i; pri[++pri[0]]=i; } for(int j=1;j<=pri[0];j++) { if(i*pri[j]>10000)break; to[i*pri[j]]=pri[j]; if(i%pri[j]==0)break; } } }