【XSY2668】排列统计 DP

题目描述

  给你一个长度为\(n\)的排列\(a\),每次要选择两个数,交换这两个数(这两个数可以相同)。总共要交换\(k\)次。

  最后要统计数列中有多少位置\(i\)满足\(\max_{j\leq i}a_i=a_i\)。求前面这个东西的期望。

  \(n\leq 100,k\leq 80\)

题解

  我们枚举每个数\(y\)每在个位置\(x\)的贡献。把其他数中大于\(y\)的看成\(1\),把其他数中小于\(y\)的看成\(0\),然后DP。

  设\(f_{i,j,k}\)为交换了\(i\)次,\(1\)~\(x-1\)\(j\)\(1\),(\(k\)在下面解释)的方案数

  两条竖线中间是位置\(x\)

  \(k=0\)\(|y|\)

  \(k=1\)\(y|0|\)

  \(k=2\)\(y|1|\)

  \(k=3\)\(|0|y\)

  \(k=4\)\(|1|y\)

  转移很多很繁琐,大家自己去推吧。。。

  时间复杂度:总共有\(O(n^2)\)次DP,每次\(O(nk)\),总的时间复杂度是\(O(n^3k)\)

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<ctime>
#include<cstdlib>
#include<utility>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
void open(const char *s)
{
#ifndef ONLINE_JUDGE
	char str[100];
	sprintf(str,"%s.in",s);
	freopen(str,"r",stdin);
	sprintf(str,"%s.out",s);
	freopen(str,"w",stdout);
#endif
}
const ll p=1000000007;
ll fp(ll a,ll b)
{
	ll s=1;
	for(;b;b>>=1,a=a*a%p)
		if(b&1)
			s=s*a%p;
	return s;
}
int x,y,i,j,k;
int n,m;
int a[100010];
ll f[90][110][5];
void add(ll &a,ll b)
{
	a=(a+b)%p;
}
ll qian0(){return (k==1||k==2)?x-2-j:x-1-j;}
ll qian1(){return j;}
ll hou0(){return (k==2?y+j-x+1:(k==3?y+j-x-1:y+j-x));}
ll hou1(){return (k==2||k==4)?n-y-j-1:n-y-j;}
ll qian0(int k){return (k==1||k==2)?x-2-j:x-1-j;}
ll qian1(int k){return j;}
ll hou0(int k){return (k==2?y+j-x+1:(k==3?y+j-x-1:y+j-x));}
ll hou1(int k){return (k==2||k==4)?n-y-j-1:n-y-j;}
int now(){return (k==1||k==3)?0:((k==2||k==4)?1:-1);}
int where(){return (k==1||k==2)?0:1;}
ll sqr(ll x){return x*x%p;}
ll gao()
{
	memset(f,0,sizeof f);
	int h=0,hh;
	for(i=1;i<x;i++)
		if(a[i]>y)
			h++;
	for(i=1;i<=n;i++)
		if(a[i]==y)
		{
			hh=i;
			break;
		}
	if(hh==x)
		f[0][h][0]=1;
	else if(hh<x)
		if(a[x]<y)
			f[0][h][1]=1;
		else
			f[0][h][2]=1;
	else
		if(a[x]<y)
			f[0][h][3]=1;
		else
			f[0][h][4]=1;
	for(i=0;i<m;i++)
		for(j=0;j<y;j++)
		{
			for(k=0;k<=4;k++)
				if(f[i][j][k])
				{
					add(f[i+1][j][k],f[i][j][k]*sqr(qian0()+qian1()));
					add(f[i+1][j][k],f[i][j][k]*sqr(hou0()+hou1()));
					add(f[i+1][j][k],f[i][j][k]*2*qian0()%p*hou0());
					add(f[i+1][j][k],f[i][j][k]*2*qian1()%p*hou1());
					add(f[i+1][j][k],f[i][j][k]);
					if(j)
						add(f[i+1][j-1][k],f[i][j][k]*2*qian1()%p*hou0());
					if(j<y-1)
						add(f[i+1][j+1][k],f[i][j][k]*2*qian0()%p*hou1());
					if(k)
						add(f[i+1][j][k],f[i][j][k]);
				}
			if(f[i][j][0])
			{
				add(f[i+1][j][1],f[i][j][0]*2*qian0(0));
				if(j)
					add(f[i+1][j-1][2],f[i][j][0]*2%p*qian1(0));
				add(f[i+1][j][3],f[i][j][0]*2*hou0(0));
				add(f[i+1][j][4],f[i][j][0]*2*hou1(0));
			}
			if(f[i][j][1])
			{
				add(f[i+1][j][0],f[i][j][1]*2);
				add(f[i+1][j][1],f[i][j][1]*2*(qian0(1)+qian1(1)));
				add(f[i+1][j][3],f[i][j][1]*2*hou0(1));
				if(j<y-1)
					add(f[i+1][j+1][3],f[i][j][1]*2%p*hou1(1));
				add(f[i+1][j][1],f[i][j][1]*2*(qian0(1)+hou0(1)));
				add(f[i+1][j][2],f[i][j][1]*2*hou1(1));
				if(j)
					add(f[i+1][j-1][2],f[i][j][1]*2%p*qian1(1));
			}
			
			if(f[i][j][2])
			{
				if(j<y-1)
					add(f[i+1][j+1][0],f[i][j][2]*2);
				add(f[i+1][j][2],f[i][j][2]*2*(qian0(2)+qian1(2)));
				add(f[i+1][j][4],f[i][j][2]*2*hou0(2));
				if(j<y-1)
					add(f[i+1][j+1][4],f[i][j][2]*2%p*hou1(2));
				add(f[i+1][j][1],f[i][j][2]*2*hou0(2));
				if(j<y-1)
					add(f[i+1][j+1][1],f[i][j][2]*2%p*qian0(2));
				add(f[i+1][j][2],f[i][j][2]*2*(qian1(2)+hou1(2)));
			}
			
			if(f[i][j][3])
			{
				add(f[i+1][j][0],f[i][j][3]*2);
				add(f[i+1][j][3],f[i][j][3]*2*(hou0(3)+hou1(3)));
				add(f[i+1][j][1],f[i][j][3]*2*qian0(3));
				if(j)
					add(f[i+1][j-1][1],f[i][j][3]*2*qian1(3));
				add(f[i+1][j][3],f[i][j][3]*2*(qian0(3)+hou0(3)));
				add(f[i+1][j][4],f[i][j][3]*2*hou1(3));
				if(j)
					add(f[i+1][j-1][4],f[i][j][3]*2*qian1(3));
			}
			
			if(f[i][j][4])
			{
				add(f[i+1][j][0],f[i][j][4]*2);
				add(f[i+1][j][4],f[i][j][4]*2*(hou0(4)+hou1(4)));
				add(f[i+1][j][2],f[i][j][4]*2*qian0(4));
				if(j)
					add(f[i+1][j-1][2],f[i][j][4]*2*qian1(4));
				add(f[i+1][j][3],f[i][j][4]*2*hou0(4));
				if(j<y-1)
					add(f[i+1][j+1][3],f[i][j][4]*2*qian0(4));
				add(f[i+1][j][4],f[i][j][4]*2*(qian1(4)+hou1(4)));
			}
		}
	return f[m][0][0];
}
int main()
{
	open("pltj");
	scanf("%d%d",&n,&m);
	int i;
	for(i=1;i<=n;i++)
		scanf("%d",&a[i]);
	ll ans=0;
	for(x=1;x<=n;x++)
		for(y=1;y<=n;y++)
			if(y>=x)
				ans=(ans+gao())%p;
	ans=ans*fp(fp(n,2*m),p-2)%p;
	printf("%lld\n",ans);
	return 0;
}
posted @ 2018-03-06 12:47  ywwyww  阅读(244)  评论(0编辑  收藏  举报