5.8.1关于n!的一个问题:
方法1:
//计算n!中有多少质因子p
int cal(int n, int p)
{
int ans=0;
for(int i=2; i<=n; i++) //从2开始遍历一直到n表示n!
{
int temp=i;
while(temp%p==0) //只要temp还是p的倍数则进行统计
{
ans++; //p的个数加1
temp/=p;
}
}
return ans;
}
方法2:
//计算n!中有多少质因子p
int cal(int n,int p)
{
int ans=0;
while(n!=0)
{
ans+=n/p; //n/p表示质因子p的个数
n/=p; //再改变n的值n/p
}
}
方法3:
int cal(int n, int p)
{
if(n<p) //n<p时候,返回0
return 0;
return n/p+cal(n/p,p);
}
5.8.2 组合数的计算:
什么是组合数:
方法1:
long long c(long long n, long long m)
{
long long ans=1; //ans初值一定设置为1
for(long long i=1; i<=n; i++)
ans*=i;
for(long long i=1; i<=m; i++)
ans/=i;
for(long long i=1; i<=n-m; i++)
ans/=i;
return ans;
}
方法2:
long long c(long long n, long long m)
{
if(m==0 || m==n)
return 1;
return C(n-1,m)+C(n-1,m-1);
}
上面代码会涉及重复计算,所以进行如下调整
long long res[67][67]={0};
long long c(long long n, long long m)
{
if(m==0 || m==n)
return 1;
if(res[n][m]!=0)
return res[n][m];
return res[n][m]=c(n-1,m)+c(n-1,m-1);
}
或者用表格的方式:
const int n=60;
void calC()
{
for(int i=0; i<=n; i++)
{
res[i][0]=res[i][i]=1; //初始化边界
}
for(int i=2; i<=n; i++)
{
for(int j=0; j<=i/2; j++)
{
res[i][j]=res[i-1][j]+res[i-1][j-1] //递推C(i,j)
res[i][i-j]=res[i][j];
}
}
}
方法3:
long long C(long long n, long long m)
{
long long ans=1;
for(long long i=1; i<=m; i++)
{
ans=ans*(n-m+i)/i; //注意一定要先乘后除
}
return ans;
}
如何计算如下问题:
方法1:通过递推公式:
递归:
int res[1010][1010]={0};
int C(int n, int m, int p)
{
if(m==0 || m==n)
return 1;
if(res[n][m]!=0) //已经有值
return res[n][m];
return res[n][m]=(C(n-1,m)+C(n-1,m-1))%p; //赋值并返回
}
递推:
void calC()
{
for(int i=0; i<=n; i++)
{
res[i][0]=res[i][i]=1; //初始化边界
}
for(int i=2; i<=n; i++)
{
for(int j=0; j<=i/2; j++)
{
res[i][j]=(res[i-1][j]+res[i-1][j-1])%p;
res[i][i-j]=res[i][j];
}
}
}
方法2:根据定义:
方法3:通过定义式进行计算:
方法4:Lucas定理:
int Lucas(int n,int m)
{
if(m==0)
return 1;
return C(n%p,m%p)*Lucas(n/p,m/p)%p; //C是计算组合数的函数
}