求组合数
1.公式法
根据组合数递推公式求解
题目描述:
代码实现:
#include<iostream>
using namespace std;
const int N=2005,p=1e9+7;
long long dp[N][N];
void init(){
for(int i=0;i<=2000;i++){
for(int j=0;j<=i;j++){
if(j==0)dp[i][j]=1;
else dp[i][j]=(dp[i-1][j]+dp[i-1][j-1])%p;
}
}
}
int main(){
int n;
cin>>n;
init();
while(n--){
int a,b;
cin>>a>>b;
cout<<dp[a][b]<<endl;
}
return 0;
}
2.快速幂加逆元
题目描述:
代码实现:
#include<iostream>
using namespace std;
#define int long long
const int N=1e5+5,p=1e9+7;
int f[N],inf[N];
int quick(int a,int b){
int res=1;
while(b){
if(b&1)res=res*a%p;
a=a*a%p;
b>>=1;
}
return res;
}
signed main(){
int n;
cin>>n;
f[0]=inf[0]=1;
for(int i=1;i<=N;i++){
f[i]=f[i-1]*i%p;//求i的阶乘
inf[i]=inf[i-1]*quick(i,p-2)%p;//利用费马小定理求i的阶乘的逆元
}
while(n--){
int a,b;
scanf("%lld%lld",&a,&b);
cout<<f[a]*inf[a-b]%p*inf[b]%p<<endl;//套公式求组合数
}
return 0;
}
3.卢卡斯定理
根据lucas定理求解组合数
其中组合数的直接求解方法是利用方法二的快速幂加逆元
代码实现:
#include<iostream>
using namespace std;
#define int long long
int p;
//用来求除法逆元
int quick(int a,int b,int p){
int res=1;
while(b){
if(b&1)res=res*a%p;
a=a*a%p;
b>>=1;
}
return res;
}
int C(int a,int b,int p){
int res=1;
//直接利用原始公式求解组合数
for(int i=a,j=1;j<=b;j++,i--){
res=res*i%p;
res=res*quick(j,p-2,p)%p;
}
return res;
}
int lucas(int a,int b,int p){
if(a<p&&b<p)return C(a,b,p);//如果a和b都同时小于p,则可以直接求解组合数
return C(a%p,b%p,p)*lucas(a/p,b/p,p)%p;//否则递归套公式降低系数求解组合数
}
signed main(){
int n;
cin>>n;
while(n--){
int a,b;
cin>>a>>b>>p;
cout<<lucas(a,b,p)<<endl;//直接套公式
}
return 0;
}
4.不带模数的组合计数
先对组合数进行分解质因数,再利用高精度乘法求解组合数
其中分解质因数利用线性筛
代码实现:
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int N=5005;
int prime[N],vis[N],cnt;
int sum[N];
void init(int n){
for(int i=2;i<=n;i++){
if(!vis[i])prime[cnt++]=i;
for(int j=0;prime[j]*i<=n;j++){
vis[prime[j]*i]=1;
if(i%prime[j]==0)break;
}
}
}
int get(int n,int p){
int res=0;
while(n){
res+=n/p;
n/=p;
}
return res;
}
vector<int> mul(vector<int>a,int b){
vector<int>c;
int t=0;
for(int i=0;i<a.size();i++){
t+=a[i]*b;
c.push_back(t%10);
t/=10;
}
while(t){
c.push_back(t%10);
t/=10;
}
return c;
}
int main(){
int a,b;
cin>>a>>b;
init(a);
for(int i=0;i<cnt;i++){
int p=prime[i];
sum[i]+=get(a,p)-get(b,p)-get(a-b,p);
}
vector<int>res;
res.push_back(1);
for(int i=0;i<cnt;i++){
for(int j=0;j<sum[i];j++){
res=mul(res,prime[i]);
}
}
for(int i=res.size()-1;i>=0;i--)cout<<res[i];
return 0;
}