题意:给你 a,n,m, 求a^( C(n,m) ) )% mod,mod = 999911659。
题解:组合数取模再加上题目的数据范围是肯定要用lucas定理的,但是根据 欧拉定理可知ans = a^( C(n, m) %(mod-1) + mod-1 ) %mod,因为这里mod是一个质数,所以mod-1就不是一个质数,而lucas要求取模的模数一定是质数,所以不好直接用lucas定理。那么我们可以把mod-1分解质因数(mod-1拆成素数相乘为2*3*4679*35617,可以直接打表给出),然后用lucas定理分别求C(n, m)) % m, m = 2, 3, 4679, 35617,因为模都是互质的数,所以用中国剩余定理合并它们然后快速幂求解最后的答案即可。
需要注意: 欧拉定理的使用条件是gcd(a,mod)==1,如果a==mod则要输出0。
附上代码:
#include<iostream>
#include<algorithm>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<math.h>
#include<queue>
const int mod=999911659;
const int inf=2147483640;
typedef long long LL;
using namespace std;
int t[4]= {2,3,4679,35617};
int n,m,aa,r[4],fac[4][100010];
int power(LL a,int b,LL c)//快速幂
{
a%=c;
LL res=1;
while (b)
{
if (b&1) res=res*a%c;
b>>=1;
a=a*a%c;
}
return res;
}
int C(int n,int m,int p) //组合数
{
if (m<n) return 0;
return (LL)(fac[p][m]*power((LL)fac[p][n]*fac[p][m-n],t[p]-2,t[p]))%t[p];
}
int Lucas(int n,int m,int p) //卢卡斯定理
{
if (m==0) return 1;
return C(n%t[p],m%t[p],p)*Lucas(n/t[p],m/t[p],p)%t[p];
}
void exgcd(int a,int b,LL &x,LL &y)//扩展欧几里得
{
if (b==0)
{
x=1,y=0;
return;
}
exgcd(b,a%b,y,x);
y-=a/b*x;
}
int CRT()//中国剩余定理
{
LL x,y,M=t[0],R=r[0];
for (int i=1; i<4; i++)
{
int mm=t[i],rr=r[i];
exgcd(M,mm,x,y);
x=((rr-R)*x%mm+mm)%mm;
R+=M*x;
M*=mm;
}
return R;
}
int main()
{
while(scanf("%d%d%d",&aa,&n,&m)!=EOF){
memset(fac,0,sizeof(fac));
memset(r,0,sizeof(r));
if (aa==mod)
{
printf("0\n");
return 0;
}
for (int i=0; i<4; i++)
{
fac[i][0]=1;
for (int j=1; j<=t[i]; j++)
fac[i][j]=fac[i][j-1]*j%t[i];
}
for (int i=0; i<4; i++)
{
r[i]=(r[i]+Lucas(m,n,i))%t[i];
}
printf("%d\n",power(aa,CRT(),mod));
}
return 0;
}