大组合数取模——fzu 2020(可做模板)

http://blog.csdn.net/swm8023/article/details/6525980

比较好的资料

 

求C(10,3,107)

第一步: 10/3

第二步: *9/2

第三步:*8/1

如第一步里会出现除不下时的情况,用中国剩余定理做

View Code
#include<stdio.h>

long long min(long long a,long long b)
{
if(a>b)return b;
else return a;
}

long long ext_gcd(long long a,long long b,long long &x,long long &y)
{
if(b==0){x=1,y=0;return a;}
long long res=ext_gcd(b,a%b,y,x);
y-=a/b*x;
return res;
}

long long retx(long long a,long long b,long long n)
{
long long res,x,y,t;
res=ext_gcd(a,b,x,y);
if(n%res==0)
{
x=x*n/res;
t=b/res;
if(t<0)t=-t;
x=(x%t+t)%t;
return x;
}
return -1;
}

long long Cfun(long long n,long long m,long long p)
{
long long up=n,all=1,i;
long long down=m;
for(i=1;i<=m;i++)
{
all=all*up;
all=all%p;

if(all%down==0)
all=all/down;
else
all=retx(down,p,all);
down--;
up--;
}
return all;
}

int main()
{
long long n,m,p,t,i;
scanf("%lld",&t);
while(t--)
{
scanf("%lld%lld%lld",&n,&m,&p);
m=min(m,n-m);
printf("%lld\n",Cfun(n,m,p));
}
}


lucas定理过的,小数据量时速度不明显

View Code
#include<iostream>
#include<stdio.h>
using namespace std;
int pow_mod(int a,int n,int p)
{
int ans=1,t=a;
while(n)
{
if(n&1)
ans=(long long)ans*t%p;
t=(long long)t*t%p;
n>>=1;
}
return ans;
}
int cal(int n,int m,long p)
{
if(m>n-m) m=n-m;
int ans=1;
for(int i=1;i<=m;i++)
{
ans=(long long)ans*(n-i+1)%p;
int a=pow_mod(i,p-2,p);
ans=(long long)ans*a%p;
}
return ans;
}

int com_mod(int n,int m,long p)
{
if(n<m)return 0;
return cal(n,m,p);
}

int lucas(int n,int m,long p)
{
int r=1;
while(n&&m&&r)
{
r=(long long)r*com_mod(n%p,m%p,p)%p;
n/=p;
m/=p;
}
return r;
}

int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m,p;
scanf("%d%d%d",&n,&m,&p);
printf("%d\n",lucas(n,m,p));
}
}



你可能感兴趣的:(模板)