首先我们可以简化一下条件,显然只要满足相邻元素满足限制即可。即对于任意的相邻的 i,j 满足 max{hi,hj}>=|xi−xj|
考虑如果我们已经知道排列的顺序,那么我们很容易统计这种顺序下的答案:
设 S=∑n−1i=1max{hi,hi+1} ,则相当于选 n 个非负整数,加和不大于
S 小于
复杂度
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=100105;
int n,m,MOD,f[2][10105][115],ans;// f[i][s][j]
LL inv[maxn],fac[maxn],fac_inv[maxn];
LL C(int n,int m){ return fac[n]*fac_inv[m]%MOD*fac_inv[n-m]%MOD; }
int main(){
scanf("%d%d%d",&n,&m,&MOD); m=m-1+n; // m=X-1+n C(m-S,n)
fac[0]=1; for(int i=1;i<=100100;i++) fac[i]=fac[i-1]*i%MOD;
inv[1]=1; for(int i=2;i<=100100;i++) inv[i]=(LL)(MOD-MOD/i)*inv[MOD%i]%MOD;
fac_inv[0]=1; for(int i=1;i<=100100;i++) fac_inv[i]=fac_inv[i-1]*inv[i]%MOD;
f[1][0][0]=1;
for(int i=1;i<=n-1;i++){
memset(f[(i&1)^1],0,sizeof(f[(i&1)^1]));
for(int s=0;s<=i*i&&s<=m-n;s++)
for(int j=0;j<=i-1;j++) if(f[i&1][s][j]){
LL f_now=f[i&1][s][j];
if(j){
(f[(i&1)^1][s][j+1]+=f_now*j%MOD)%=MOD;
(f[(i&1)^1][s+(i+1)][j]+=f_now*j*2%MOD)%=MOD;
(f[(i&1)^1][s+2*(i+1)][j-1]+=f_now*j%MOD)%=MOD;
}
(f[(i&1)^1][s][j+1]+=f_now*2%MOD)%=MOD;
(f[(i&1)^1][s+(i+1)][j]+=f_now*2%MOD)%=MOD;
}
}
for(int s=0;s<=n*n&&s<=m-n;s++) (ans+=C(m-s,n)*f[n&1][s][0]%MOD)%=MOD;
printf("%d\n",ans);
return 0;
}