考虑直接选择n个不相同的数 可以轻易设计一个dp
f[i][j] = f[i-1][j] + i f[i-1][j-1]
用归纳法可以证明 F(i,j)是一个关于i的2j次多项式 可以通过得到i=1...2n+1的值来插出答案暴力dp时间复杂度O(n^2)
暴力插出多项式的时间复杂度是O(n^3)但我们只要单点求值 套用拉格朗日插值即可 时间复杂度O(n) 但是这里由于前面是O(n^2)完全可以O(n^2)来暴力计算下面这个式子。
总时间复杂度O(n^2)
整天写这种<1K的题还有什么前途…
#include"bits/stdc++.h"
using namespace std;
const int N=505;
typedef long long LL;
int f[2*N][N],x,n,P,ans,m;
int inv(int a,int t=P-2){
int r=1;
while(t){
if(t&1)r=(LL)r*a%P;
a=(LL)a*a%P;t>>=1;
}
return r;
}
int main(){
cin>>x>>n>>P;
f[0][0]=1;m=2*n+1;
for(int i=1;i<=m;i++)for(int j=f[i][0]=1;j<=n;j++)f[i][j]=(f[i-1][j]+(LL)i*f[i-1][j-1])%P;
for(int i=1;i<=m;i++){
int a=f[i][n],b=1;
for(int j=1;j<=m;j++)if(i!=j)a=(LL)a*(x-j)%P,b=(LL)b*(i-j)%P;
a=(LL)a*inv(b)%P;
ans=(ans+a)%P;
}
for(int i=1;i<=n;i++)ans=(LL)ans*i%P;
cout<<(ans+P)%P;
return 0;
}