求解组合数取模模板

来源:互联网 发布:淘宝咸鱼网手机版 编辑:程序博客网 时间:2024/06/05 23:53
#include <stdio.h>#include <string.h>#include <algorithm>#include <vector>using namespace std;typedef long long ll;/*    方案一:暴力求解,C(n,m)=n*(n-1)*...(n-m+1)/m!, n<15*/int C1(int n,int m){int Mod = 10007;int ans=1;for(int i=n;i>=(n-m+1);i--)ans*=i;while(m)    ans/=m--;return ans%Mod;}/*    方案二:打表,利用杨辉三角,C(n,m)=C(n-1.m-1)+C(n-1,m),n<1000*/const int N = 1e4+5;int C[N][N];void C2(){int Mod = 10007;memset(C,0,sizeof(C));for(int i=0;i<=1000;i++){for(int j=0;j<=i;j++){if(j==0||j==i)C[i][j]=1;else C[i][j]=(C[i-1][j]+C[i-1][j-1])%Mod;}}//for(int i=0;i<=10;i++){//for(int j=0;j<=i;j++){//printf("%d ",C[i][j]);//}//printf("\n");//}}/*    方案三:质因数分解,C(n,m)=n!/(m!*(n-m)!)*///利用筛法生成素数const int MAXN = 1e6;int prime[MAXN+1]={0};vector<int> P(){vector<int> pr;int i,j;pr.push_back(2);for(i=3;i*i<=MAXN;i=i+2){if(!prime[i]){pr.push_back(i);for(j=i*i; j<MAXN; j+=i)prime[j]=1;}}while(i<=MAXN){if(!prime[i])pr.push_back(i);i+=2;}return pr;}//计算n!中的素因子p的指数int Cal(int x,int p){int ans=0;ll rec =p;while(x>=rec){ans+=x/rec;rec*=p;}return ans;}//计算n的k次方对M取模,二分法int Pow(ll n, int k, int Mod){ll ans=1;while(k){if(k&1)ans=(ans*n)%Mod;n = (n*n)%Mod;k>>=1; //k=k>>1  k=k/2;}return ans;}//计算C(n,m)ll C3(int n,int m){const int Mod = 10007;vector<int> pr = P();ll ans=1;int num;for(int i=0;i<pr.size()&&pr[i]<=n;i++){num = Cal(n,pr[i])-Cal(m,pr[i])-Cal(n-m,pr[i]);ans = (ans*Pow(pr[i],num,Mod))%Mod;}return ans;}/*    方案四:利用Lucas定理*/ll f[N+5];  //打表,记录n!,避免重复计算int Mod = 10007;//求最大公约数,欧几里得ll gcd(ll a,ll b){if(b==0) return 1;return gcd(b,a%b);}//扩展欧几里得ll x,y;void Extend_gcd(ll a,ll b){if(b==0){x=1;y=0;}else{Extend_gcd(b,a%b);ll t=x;x=y;y=t-(a/b)*y;}}//计算不大的C(n,m)ll CC(ll a,ll b){if(b>a) return 0;b=(f[a-b]*f[b])%Mod;a=f[a];ll c=gcd(a,b);a/=c;b/=c;Extend_gcd(b,Mod);x=(x+Mod)%Mod;x=(x*a)%Mod;return x;}//Lucas定理ll C4(ll n,ll m){ll ans=1,a,b;while(m||n){a=n%Mod;b=m%Mod;n/=Mod;m/=Mod;ans=(ans*CC(a,b)%Mod);}return ans;}int main(){printf("%d\n",C1(1000,5));C2();printf("%d\n",C[1000][5]);printf("%d\n",C3(1000000,5));f[0]=1;for(int i=1;i<=Mod;i++)   //预计算n!f[i]=(f[i-1]*i)%Mod;printf("%d\n",C4(1000000,5));return 0;}

0 0