组合数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("\n");
}
}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;
}
}
}