考虑dp的话是
f
[
i
]
[
j
]
=
i
∗
f
[
i
−
1
]
[
j
−
1
]
+
f
[
i
−
1
]
[
j
]
f[i][j]=i*f[i-1][j-1]+f[i-1][j]
f[i][j]=i∗f[i−1][j−1]+f[i−1][j]分别表示选当前这个数和不选
然而
i
i
i很大,有1e9
发现每次转移乘上的是一个
i
i
i,且
j
+
1
j+1
j+1,类似一个前缀和,所以
i
i
i的最高次项为
2
n
2n
2n
则dp出
2
n
+
1
2n+1
2n+1项做拉格朗日插值就完了
Code:
#include<bits/stdc++.h>
using namespace std;
const int rlen=1<<21|1;
inline char gc(){
static char ibuf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,rlen,stdin));
return (ib==ob)?EOF:*ib++;
}
inline int read(){
int res=0,f=1;char ch=gc();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=gc();}
while(isdigit(ch)) {res=(res+(res<<2)<<1)+(ch^48);ch=gc();}
return res*f;
}
int mod;
inline void file(){freopen("lx.in","r",stdin),freopen("lx.out","w",stdout);}
inline int add(int x,int y){x+=y;if(x>=mod) x-=mod;return x;}
inline int dec(int x,int y){x-=y;if(x<0) x+=mod;return x;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline void inc(int &x,int y){x+=y;if(x>=mod) x-=mod;}
inline void Dec(int &x,int y){x-=y;if(x<0) x+=mod;}
inline void Mul(int &x,int y){x=mul(x,y);}
inline int ksm(int a,int b){int res=1;for(;b;b>>=1,a=mul(a,a)) if(b&1) res=mul(res,a);return res;}
const int N=1005;
int n,A;
int dp[N][N];
int fac[N];
inline void init(){
fac[0]=1;
for(int i=1;i<=n*2;i++) fac[i]=mul(fac[i-1],i);
dp[0][0]=1;
for(int i=1;i<=n*2+1;i++){
dp[i][0]=1;
for(int j=1;j<=n;j++) dp[i][j]=add(mul(i,dp[i-1][j-1]),dp[i-1][j]);
}
}
inline int lagrange(){
int m=n<<1;
if(A<=m+1) return dp[A][n];
int res=0;
for(int i=1;i<=m+1;i++){
int tmp=mul(mul(fac[i-1],fac[m-i+1]),dec(A,i));
tmp=ksm(tmp,mod-2);if((m-i+1)&1) Mul(tmp,dec(0,1));
Mul(tmp,dp[i][n]);inc(res,tmp);
}
for(int i=1;i<=m+1;i++) Mul(res,dec(A,i));
return res;
}
int main(){
A=read();n=read();mod=read();
init();
cout<<mul(fac[n],lagrange());
return 0;
}