• 【agc030f】Permutation and Minimum(动态规划)


    【agc030f】Permutation and Minimum(动态规划)

    题面

    atcoder
    给定一个长度为(2n)的残缺的排列(A),定义(b_i=min{A_{2i-1},A_{2i}}),求有多少种不同的(b)

    题解

    考虑这个(b)的取值是两两配对之后求(min),所以我们把所有的数按照从大往小处理,这样子就可以在每一对数填好的时候计算贡献。
    首先把已经确定的(b)直接丢掉。这样子剩下了若干个填了一半和没有填的对。
    (f[i][j][k])表示当前考虑到第(i)个数,还剩下(j)对填了一个数的((-1,-1))对和(k)对未匹配的((x,-1))对。
    暂时不用考虑对与对之间的顺序关系,最后把由两个(-1)组成的配对拿出来乘一个阶乘就好了。
    考虑新加入的这个数。它有两种贡献,第一种是和一个填了一半的进行配对,另外一个是自己产生一个填了一半的配对。
    分类讨论,考虑它是不是((x,-1))对中的一个(x)
    如果不是,那么可以考虑填入一个((-1,-1))对中的一个,那么转移到(f[i][j+1][k]),要么匹配掉一个((-1,-1))对,变成(f[i][j-1][k]),要么匹配一个((x,-1))对,这里有(k)种匹配方法,所以乘(k)后转移到(f[i][j][k-1])
    如果是,那么要么不匹配,转移到(f[i][j][k+1]),要么拉一个填了一半的((-1,-1))对过来,转移到(f[i][j-1][k])

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define MOD 1000000007
    #define MAX 305
    void add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;}
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    int n,m,ans,a[MAX<<1];
    int cnt1,cnt2,f[MAX<<1][MAX][MAX];
    int S[MAX<<1];
    bool vis[MAX<<1],book[MAX<<1];
    int main()
    {
    	n=read();
    	for(int i=1;i<=n+n;++i)a[i]=read();
    	for(int i=1;i<=n+n;i+=2)
    		if(a[i]==-1&&a[i+1]==-1)++cnt1;
    		else if(a[i]>0&&a[i+1]>0)vis[a[i]]=vis[a[i+1]]=true;
    		else ++cnt2,book[(~a[i])?a[i]:a[i+1]]=true;
    	for(int i=n+n;i;--i)if(!vis[i])S[++m]=i;
    	f[0][0][0]=1;
    	for(int i=1;i<=m;++i)
    		for(int j=0;j<=cnt1+cnt2;++j)
    			for(int k=0;k<=cnt2;++k)
    			{
    				if(!f[i-1][j][k])continue;
    				if(!book[S[i]])
    				{
    					add(f[i][j+1][k],f[i-1][j][k]);
    					if(j)add(f[i][j-1][k],f[i-1][j][k]);
    					if(k)add(f[i][j][k-1],1ll*k*f[i-1][j][k]%MOD);
    				}
    				else
    				{
    					add(f[i][j][k+1],f[i-1][j][k]);
    					if(j)add(f[i][j-1][k],f[i-1][j][k]);
    				}
    			}
    	ans=f[m][0][0];for(int i=1;i<=cnt1;++i)ans=1ll*ans*i%MOD;
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    IE 下 telerik RadAjaxManager 多次请求,LoadingPanel 点击消失
    Razor 越来越像 Rails 了
    MongoDB 初学
    Virtual PC 2007 SP1 中,Windows Server 2008 SP2 下安装 SQL Server 2008 R2
    VB 程序员:不要放松对自己的要求
    Linq to SQL bug: Char(1) maps to System.Char
    Linq to SQL: System.InvalidCastException: Specified cast is not valid
    ASP.NET 4: 允许对URL中的特殊字符串放宽要求
    IE 8 打开新 Tab 页报错 window.external.BuildNewTabPage()
    过完年了
  • 原文地址:https://www.cnblogs.com/cjyyb/p/10486411.html
Copyright © 2020-2023  润新知