Froggy
2021-07-04 13:56:15
来一个非常暴力的做法。
地理学考的时候想的
看见排列还有字典序,一个显然的想法就是枚举排列
假设最长公共前缀是
分别设
由于
那么现在的问题就变成了求有多少对长度为
从小到大一个一个插到排列里,直接暴力 dp 是
插入
暴力乘上分子,然后除以
时间复杂度:
code:
#include<bits/stdc++.h>
using namespace std;
#define N 505
typedef long long ll;
const int B=251*501;
int n,mod,dp[2][N*N],ans,A[N];
int main(){
n=read(),mod=read();
A[0]=1;
for(int i=1;i<=n;++i){
A[i]=1LL*A[i-1]*(n-i+1)%mod;
}
dp[0][B]=1;
#define update(x,y) x=(x+y)%mod
for(int i=1;i<n;++i){
memset(dp[i&1],0,sizeof(dp[i&1]));
int C=(i+1)*(i+1)/2;
for(int j=B-C;j<=B+C;++j){
int w=dp[(i-1)&1][j];
if(w){
update(dp[i&1][j+i+1],w);
update(dp[i&1][j-i+1],w);
update(dp[i&1][j+1],1LL*(mod-2)*w);
}
}
int zyk=2;
while(zyk--){
for(int j=B+C;j>=B-C;--j){
update(dp[i&1][j],dp[i&1][j+1]);
}
for(int j=B-C;j<=B+C;++j)dp[i&1][j]=dp[i&1][j+1];
}
static int suf[N*N];
for(int j=C;j>=0;--j){
suf[j]=(suf[j+1]+dp[i&1][B+j])%mod;
}
for(int a=0;a<=i;++a){
for(int b=a+1;b<=i;++b){
update(ans,1LL*A[n-i-1]*suf[b-a+1]);
}
}
}
printf("%d\n",ans);
return 0;
}