JZOJ 5921. 【NOIP2018模拟10.21】种花

题目

一个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(ji)(aiaj)
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
#include
#include
#include
#include
#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;
}

你可能感兴趣的:(排列组合,容斥,错排)