这是我的C函数:
int C(int n,int m,int p,int pr){
if(n<m)return 0;
long long f1=fac(n,p,pr),f2=fac(m,p,pr),f3=fac(n-m,p,pr),vt=0;
for(int i=p;i<=n;i*=p)vt+=n/i;
for(int i=p;i<=m;i*=p)vt-=m/i;
for(int i=p;i<=n-m;i*=p)vt-=(n-m)/i;
return ksm(p,vt,pr)*f1%pr*ksm(f2,pr-pr/p-1,pr)%pr*ksm(f3,pr-pr/p-1,pr)%pr;
}
可以看到我求fac函数的逆元时是用的ksm(f2,pr-pr/p-1,pr),但正常不应该是用扩欧求吗。当时自己抄的一个神秘代码直接过了,不过用ksm(f2,pr-2,pr)是正常的WA 80pts。
如果ksm(f2,pr-pr/p-1,pr)真是f2的逆元,那么fpr−pr−1−1f≡1,也就是fpr−pr−1≡1,什么鬼啊……
附源代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
int exgcd(int a,int b,int &x,int &y){
if(b==0){
x=1,y=0;
return a;
}
int nx,ny;
int g=exgcd(b,a%b,nx,ny);
x=ny;
y=nx-a/b*ny;
return g;
}
int ksm(int a,int p,int m){
if(p==0)return 1;
long long tmp=ksm(a,p/2,m);
if(p&1)return tmp*tmp%m*a%m;
else return tmp*tmp%m;
}
int fac(int v,int p,int pr){
if(!v)return 1;
long long res=1;
for(int i=1;i<=pr;i++){
if(i%p)res=res*i%pr;
}
res=ksm(res,v/pr,pr);
for(int i=1;i<=v%pr;i++){
if(i%p)res=res*i%pr;
}
return res*fac(v/p,p,pr)%pr;
}
int C(int n,int m,int p,int pr){
if(n<m)return 0;
long long f1=fac(n,p,pr),f2=fac(m,p,pr),f3=fac(n-m,p,pr),vt=0;
for(int i=p;i<=n;i*=p)vt+=n/i;
for(int i=p;i<=m;i*=p)vt-=m/i;
for(int i=p;i<=n-m;i*=p)vt-=(n-m)/i;
return ksm(p,vt,pr)*f1%pr*ksm(f2,pr-pr/p-1,pr)%pr*ksm(f3,pr-pr/p-1,pr)%pr;
}
int exFocalors(int n,int m,int mod){
int v=mod;
vector<int>r,a;
for(int i=2;i*i<=v;i++){
if(v%i==0){
int nr=1;
while(v%i==0){
v/=i;
nr*=i;
}
int na=C(n,m,i,nr);
r.push_back(nr);
a.push_back(na);
}
}
if(v>1){
int nr=v,na=C(n,m,v,v);
r.push_back(nr);
a.push_back(na);
}
v=mod;
int ans=0;
for(int i=0,x,y;i<r.size();i++){
int g=exgcd(v/r[i],r[i],x,y);
x=(x%r[i]+r[i])%r[i];
ans=(ans+v/r[i]*a[i]*x%v)%v;
}
return ans;
}
int p,n,m,ans=1;
signed main(){
cin>>n>>m>>p;
cout<<exFocalors(n,m,p)<<endl;
}