C(m,n)%P

program1 n!%P(P为质数)

我们发现n! mod P的计算过程是以P为周期的的,举例如下:

n = 10, P = 3

n! = 1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10

= 1 * 2 *

4 * 5 *

7 * 8 *

10 *

3 * 6 * 9

= (1 * 2)^3 *

1*

3^3 * (1 * 2 * 3)

最后一步中的1 * 2 *3可递归处理。

因为P的倍数与P不互质,所以P的倍数不能直接乘入答案,应当用一个计数器变量g来保存答案中因子P的个数。

我们提前预处理出fac[i] = 1 * 2 * 3 * … * (i – 1) * i mod P,函数calcfac(n)返回n! mod P的值,power(a, b, c)返回ab mod c的值,注意,calcfac(n)算出来的值不包含因子P,我们另外把因子P的个数另外存在g中。

代码如下:

typedef long long LL;

LL calcfac(LL n)

{

if (n < P) return fac[n];

LL s = n / P, t = n % P;

LL res = power(fac[P - 1], s, P); //fac[P - 1]重复出现了s次

res = res * fac[t] % P; //除去s次fac[P – 1]外,剩下的零头

g += n / P; //提出n / P个因子P

res = res* calcfac(n / P) % P; //递归处理

return res;

}

program2 C(m,n)%P(P为质数)

运用program1,算出m!%P,n!%P和(m-n)!%P,已知这三者的答案中因子P的个数为g1,g2,g3。

我们可以得到:

我们不假思索地认为g1-g2-g3>=0(否则C(m,n)算出来就是分数了),而且容易知道calcfac(n)*falcfac(m-n)与P互质(我们除去了P因子)所以可以变成:

这样就可以直接算了。

program3 C(m,n)%P(P不一定为质数)

基本思路与program2相同。

对P进行质因数分解,得到P = p1c1 * p2c2 * … * ptct。

对于每个1≤i≤t,以pici为模运行program2,最后用中国剩余定理合并。这里pici不一定为质数,不过只需对原算法稍加修改即可。令modi = pici,fac[i] = 除去pi的倍数外i的阶乘。例如pi = 3,ci = 2,那么fac[10] = 1 * 2 * 4 * 5 * 7 * 8 * 10,除去了3的倍数3、6和9。阶乘依然是以modi为周期的,calcfac(n)与program2主体相同,只是统计因子个数时,应使用ret += n / pi而不是ret += n / modi,递归处理时也应该是calcfac(n / pi)而不是calcfac(n / modi)。

当然,这个算法也有些局限,因为要求fac数组,所以pici要比较小,如果P是一个大质数就不行了。

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<utility>
#include<set>
#include<bitset>
#include<vector>
#include<functional>

using namespace std;

typedef long long LL;
typedef double DB;
typedef pair<int,int> PII;

#define mmst(a,v) memset(a,v,sizeof(a))
#define mmcy(a,b) memcpy(a,b,sizeof(a))
#define re(i,a,b) for(i=a;i<=b;i++)
#define red(i,a,b) for(i=a;i>=b;i--)
#define fi first
#define se second

template<class T>inline T sqr(T x){return x*x;}
template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}

const DB EPS=1e-9;
inline int dblcmp(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;}

inline void SetOpen(string s)
{
freopen((s+".in").c_str(),"r",stdin);
freopen((s+".out").c_str(),"w",stdout);
}

inline int Getin_Int()
{
int res=0,flag=1;char z;
for(z=getchar();z!=EOF && z!=‘-‘ && !isdigit(z);z=getchar());
if(z==EOF)return 0;
if(z==‘-‘){flag=-flag;z=getchar();}
for(;z!=EOF && isdigit(z);res=res*10+z-‘0‘,z=getchar());
return res*flag;
}
inline LL Getin_LL()
{
LL res=0,flag=1;char z;
for(z=getchar();z!=EOF && z!=‘-‘ && !isdigit(z);z=getchar());
if(z==EOF)return 0;
if(z==‘-‘){flag=-flag;z=getchar();}
for(;z!=EOF && isdigit(z);res=res*10+z-‘0‘,z=getchar());
return res*flag;
}

const LL maxpici=100000;
const LL maxcnt=100;

LL n,m,P;
LL cnt,p[maxcnt+10],c[maxcnt+10],mod[maxcnt+10],euler[maxcnt+10],fac[maxcnt+10][maxpici+10];
LL ans;

inline LL power(LL a,LL b,LL Mod)
{
LL x=1,y=a;
while(b!=0){if(b&1)x=x*y%Mod;if(b==1)break;y=y*y%Mod;b/=2;}
return x;
}

inline LL calfac(LL N,LL id,LL &g)
{
if(N<p[id])return fac[id][N];
LL s=N/mod[id],t=N%mod[id],res=1;
res=res*power(fac[id][mod[id]-1],s,mod[id])%mod[id];
res=res*fac[id][t]%mod[id];
g+=N/p[id];
res=res*calfac(N/p[id],id,g)%mod[id];
return res;
}

inline LL solve(LL id)
{
LL g1=0,g2=0,g3=0;
LL fenzi=calfac(m,id,g1),fenmo=calfac(n,id,g2)*calfac(m-n,id,g3)%mod[id];
return fenzi*power(fenmo,euler[id]-1,mod[id])%mod[id]*power(p[id],g1-g2-g3,mod[id])%mod[id];
}

inline void extend_gcd(LL a,LL &x,LL b,LL &y)
{
if(b==0){x=1;y=0;return;}
LL dx,dy;
extend_gcd(b,dx,a%b,dy);
x=dy;
y=dx-a/b*dy;
}

int main()
{
SetOpen("program");
LL i,j,temp;
m=Getin_Int();n=Getin_Int();P=Getin_Int();
if(m<n){puts("0\n");return 0;}
temp=P;
re(i,2,maxpici)if(temp%i==0)
{
++cnt;
p[cnt]=i;
mod[cnt]=1;
while(temp%i==0){c[cnt]++;mod[cnt]*=i;temp/=i;}
euler[cnt]=mod[cnt]/p[cnt]*(p[cnt]-1);
fac[cnt][0]=1;
re(j,1,mod[cnt]-1)fac[cnt][j]=(j%p[cnt]==0)?fac[cnt][j-1]:fac[cnt][j-1]*j%mod[cnt];
}
ans=0;
re(i,1,cnt)
{
temp=solve(i);
LL a=P/mod[i],x,b=mod[i],y;
extend_gcd(a,x,b,y);
ans=(ans+temp*a%P*x%P)%P;
}
ans=(ans%P+P)%P;
cout<<ans<<endl;
return 0;
}

时间: 2024-09-28 22:30:23