题目
一个n的排列,如果满足所有的第i个位置不是p[i],则这个排列是合法的。
求所有的合法的排列的权值。
权值:
∑
j
>
i
,
a
j
<
a
i
(
j
−
i
)
∗
(
a
i
−
a
j
)
\sum_{j>i,a_j<a_i}(j-i)*(a_i-a_j)
∑j>i,aj<ai(j−i)∗(ai−aj)
p[i]是一个全排列。
n<=5000
题解
多种方法
组合数。设
f
[
x
]
[
y
]
f[x][y]
f[x][y]表示x+y个格要填x+y个数。
有2种转移的方法:考虑最后一个格是有限制的,或最后一个格是没有限制的。
然后每对(i,j)都有自己独特的贡献
分类讨论
①i占p[j],j占p[i]。
②i占p[j],j不占p[i]或i不占p[j],j占p[i]
③i不占p[j]且j不占p[i]。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 5010
#define mo 1000000009
#define LL long long
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
int i,j,k,l,n,m,ans;
int f[N][3],p[N];
int jc[N],sum[N];
int a1,a2,a3,A;
int main(){
scanf("%d",&n);
fo(i,1,n)scanf("%d",&p[i]);
f[0][0]=1;
k=1;
fo(i,1,n){
f[i][0]=1ll*i*f[i-1][0]%mo;k=-k;
f[i][0]=(f[i][0]+k+mo)%mo;
}
fo(i,1,2)f[0][i]=(1ll*f[0][i-1]*i)%mo;
fo(i,1,n)fo(j,1,2)f[i][j]=(1ll*f[i-1][j]*i+j*f[i][j-1])%mo;
A=0;
fo(i,1,n-1)A=(A+1ll*(n-i)*i)%mo;
fo(i,1,n)sum[i]=(sum[i-1]+i)%mo;
fo(i,1,n-1)fo(j,i+1,n){
a1=a2=a3=0;
if(n>=2)a1=max(0,p[j]-p[i]);
if(n>=3)a2=((sum[p[j]-1]+sum[n-p[i]])%mo-2*a1%mo+mo)%mo;
if(n>=4){
a3=((A-a1+mo)%mo-a2+mo)%mo;
a3=(a3-sum[p[i]-1]+mo)%mo;
a3=(a3-sum[n-p[j]]+mo)%mo;
a3=(a3+max(0,p[i]-p[j]))%mo;
}
ans=(ans+1ll*(j-i)*((1ll*a1*f[n-2][0]+1ll*a2*f[n-3][1])%mo+1ll*a3*f[n-4][2]%mo)%mo)%mo;
}
printf("%d",ans);
return 0;
}