• 【XSY2668】排列统计 DP


    题目描述

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

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

      (nleq 100,kleq 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
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    最新恶意IE跳窗广告IS_0518(_IS_ISC.DLL)的删除方法
    禁止UDP端口引起DNS错误导致邮局无法外发的故障
    微软某个补丁引起DCOMCNFG无法对后安装的COM进行权限设置的处理
    J2ME中使用calendar类获得当前时间
    今天实在忍不住,把极速星空的密码给破了
    准备开发一个PSP专用的网站http://www.mypsp.com.cn
    网络工程师30个经典的电脑使用技巧
    XBOX更换160G大硬盘的笑话
    PPC软件字体太小的调整
    解决IISASP调用XmlHTTP出现msxml3.dll (0x80070005) 拒绝访问的错误
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8513754.html
Copyright © 2020-2023  润新知