线性法
#include<bits/stdc++.h>
using namespace std;
const int N=1e6;
long long inv[N*3+10];
int main()
{
int i,j,k,m,n,p;
scanf("%d%d",&n,&p);
inv[1]=1;
for(i=2;i<=n;i++)
{
inv[i]=(p-p/i)*inv[p%i]%p;
}
printf("1\n");
for(i=2;i<=n;i++)
printf("%lld\n",inv[i]);
return 0;
}
快速幂法
费马小定理
我们需要求出n的阶乘 再求出分母的逆元即可,分母的逆元可以分为两部分取求 求(n-m)!的逆元 再求m!的逆元
#include<bits/stdc++.h>
using namespace std;
long long fac[2102300],inv[10101010],n,m;
const long long mod=1000000007;
long long quick(long long x,long long y)
{
long long ans=1;//利用费马小定理
while(y)
{
if(y&1)
ans=(ans*x)%mod;
y=y>>1;
x=x*x%mod;
}
return ans;
}
void getfac()
{
fac[0]=inv[0]=1;
for(int i=1;i<=20000;i++)
{
fac[i]=fac[i-1]*i%mod;//求i的阶乘
inv[i]=quick(fac[i],mod-2);//求i的阶乘的逆元
}
}
long long getans(long long n,long long m)
{
return fac[n]%mod*inv[n-m]%mod*inv[m]%mod;
}
int main()
{
int i,j,k;
getfac();
scanf("%lld%lld",&n,&m);
printf("%lld\n",getans(n,m));
return 0;
}
当n和m比较大时,上述两种方法都不能满足题目要求,这时我们利用另外一个定理
Lucas定理
证明过程不多做解释 详情在这里 Lucas定理
#include<bits/stdc++.h>
using namespace std;
const long long mod=1000000007;
//int n,m;
long long power(long long x,long long y)//这里我总是不用long long 答案总是错误
{
long long ans=1;
while(y)
{
if(y&1)
ans=(ans*x)%mod;
y=y/2;
x=x*x%mod;
}
// printf("***** %d\n",ans);
return ans;
}
long long C(long long n,long long m)
{
if(n<m)
return 0;
long long ans=1;
for(int i=1;i<=m;i++)
{
ans=ans*(((n-m+i)%mod)*power(i,mod-2)%mod)%mod;
// printf("++ %d\n",ans);
}
return ans;
}
long long Lusca(int n,int m)
{
if(m==0)
return 1;
return (Lusca(n/mod,m/mod)*C(n%mod,m%mod))%mod;
}
int main()
{
int i,j,k,n,m;
cin>>n>>m;
printf("%lld\n",Lusca(n,m));
}
再补充一下吧