zoukankan      html  css  js  c++  java
  • UOJ#506. 【JOISC2020】遗迹 动态规划

    题解

    首先,我们尝试在给定高度排列的情况下,用一种简洁的方式求出最后还剩余的柱子的坐标是哪些。容易想到如下方式:

    • 设第 (i(1leq i leq 2n)) 个柱子的高度为 (h_i),然后设一个标记数组 (f_{0..n}),初始时 (f) 没有元素被标记。考虑按照柱子编号从大到小插入柱子。假设当前插入的柱子是 (i),则找到一个最大的 (j),使得 (jleq i)(f_j) 没有被标记;如果 (j=0),那么该柱子最终没了,否则,该柱子是最后还剩余的柱子之一,并将 (f_j) 标记。

    于是,我们发现只有当 (f_1,f_2,cdots,f_{h_i}) 都被标记时,该柱子最终会消失。

    接下来我们来考虑如何计数。

    首先,同一个高度会出现两次,而且没有区别,比较棘手,我们可以将这两个值相同的高度看做不同的,并在最后给答案乘上 (frac{1}{2^n}) 去重。

    然后,我们设 (F_i) 表示使用 (i+1) 个柱子标记连续的长度为 (i+1) 的一段区间,并要求在使用前 (i) 个柱子时,该区间的第一个元素还没被标记。这可以通过简单的动态规划得到。后面的计算过程会使用 (F_i)

    定义 (g_{i,j}) 表示当前加入了第 (i,i+1,cdots, 2n) 个柱子,且 (f_1,cdots,f_j) 被标记,且 (f_{j+1}) 没有被标记,且不考虑除了与标记这些位置相关的柱子以外的柱子,在这种情况下的方案数。接下来我们考虑 (g_{i+1,j}) 会对哪些值做贡献:

    • (i+1) 号到 (2n) 号柱子中有 (cnt_0) 个最终消失,有 (cnt_1) 个最终留下。
    • (i) 号柱子最终消失:则该柱子的高度必然小于等于 (j),在小于等于 (j) 的还没被使用的高度中任选一个,由于前 (j) 种高度总共有 (2j) 个选法,为了标记 (1..j),消耗了 (j) 个,为了使之前的 (cnt_0) 个柱子消失,消耗了 (cnt_0) 个,所以还剩 (j-cnt_0) 个选法,故 (g_{i,j}+=(j-cnt_0)g_{i+1,j})
    • 否则:
      1. 如果当前柱子没有使 (f_{j+1}) 被标记,那么我们把给当前柱子取高度的问题放到之后解决,这里直接 (g_{i,j}+=g_{i+1,j})
      2. 如果当前柱子使 (f_{j+1..j+k+1}(0leq kleq cnt_1-j)) 被标记(注意我们还有 (cnt_1-j) 个柱子还没有取高度),那么我们需要在给当前柱子取高度的同时从还没有取高度的 (cnt_1-j) 个柱子里选 (k) 个取高度,使得前面的条件满足,于是就有 (g_{i,j+k+1}+=inom{cnt_1-j}{k}F_kg_{i+1,j})

    最后得到的 (frac{1}{2^n}g_{1,n}) 就是答案了。

    代码

    #include <bits/stdc++.h>
    #define clr(x) memset(x,0,sizeof (x))
    #define For(i,a,b) for (int i=(a);i<=(b);i++)
    #define Fod(i,b,a) for (int i=(b);i>=(a);i--)
    #define fi first
    #define se second
    #define kill _z_kill
    #define pb(x) push_back(x)
    #define mp(x,y) make_pair(x,y)
    #define outval(x) cerr<<#x" = "<<x<<endl
    #define outv(x) cerr<<#x" = "<<x<<"  "
    #define outtag(x) cerr<<"--------------"#x"---------------"<<endl
    #define outarr(a,L,R) cerr<<#a"["<<L<<".."<<R<<"] = ";
    	For(_x,L,R) cerr<<a[_x]<<" ";cerr<<endl;
    #define User_Time ((double)clock()/CLOCKS_PER_SEC)
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef unsigned uint;
    typedef long double LD;
    typedef vector <int> vi;
    typedef pair <int,int> pii;
    LL read(){
    	LL x=0,f=0;
    	char ch=getchar();
    	while (!isdigit(ch))
    		f=ch=='-',ch=getchar();
    	while (isdigit(ch))
    		x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    	return f?-x:x;
    }
    const int mod=1e9+7;
    int Pow(int x,int y){
    	int ans=1;
    	for (;y;y>>=1,x=(LL)x*x%mod)
    		if (y&1)
    			ans=(LL)ans*x%mod;
    	return ans;
    }
    void Add(int &x,int y){
    	if ((x+=y)>=mod)
    		x-=mod;
    }
    void Del(int &x,int y){
    	if ((x-=y)<0)
    		x+=mod;
    }
    int Add(int x){
    	return x>=mod?x-mod:x;
    }
    int Del(int x){
    	return x<0?x+mod:x;
    }
    void ckmax(int &x,int y){
    	if (x<y)
    		x=y;
    }
    void ckmin(int &x,int y){
    	if (x>y)
    		x=y;
    }
    const int N=605;
    int n;
    int a[N*2];
    int C[N][N],f[N][N],F[N],g[N*2+1][N];
    int main(){
    	n=read();
    	For(i,1,n)
    		a[read()]=1;
    	For(i,0,n){
    		C[i][0]=1;
    		For(j,1,i)
    			C[i][j]=Add(C[i-1][j-1]+C[i-1][j]);
    	}
    	f[0][0]=1;
    	For(i,1,n)
    		For(j,0,i-1){
    			int v=f[i-1][j];
    			if (!v)
    				continue;
    			Add(f[i][j],v);
    			if (j+1<=i)
    				Add(f[i][j+1],(LL)v*(j+1)*2%mod);
    			if (j+2<=i)
    				Add(f[i][j+2],(LL)v*(j+1)*(j+2)%mod);
    		}
    	For(i,0,n-1)
    		F[i]=(LL)f[i][i]*(i+2)%mod;
    	g[n*2+1][0]=1;
    	int cnt0=0,cnt1=0;
    	Fod(i,n*2,1){
    		For(j,0,n){
    			int v=g[i+1][j];
    			if (!v)
    				continue;
    			int rp0=j-cnt0;
    			int r1=cnt1-j;
    			if (a[i]==0)
    				g[i][j]=((LL)v*rp0+g[i][j])%mod;
    			else {
    				Add(g[i][j],v);
    				For(k,0,r1)
    					g[i][j+k+1]=((LL)v*F[k]%mod*C[r1][k]+g[i][j+k+1])%mod;
    			}
    		}
    		if (a[i]==0)
    			cnt0++;
    		else
    			cnt1++;
    	}
    	int ans=(LL)g[1][n]*Pow(2,mod-1-n)%mod;
    	cout<<ans<<endl;
    	return 0;
    }
    
  • 相关阅读:
    mysql 约束条件 外键 forigen key 介绍
    【洛谷P4655】Building Bridges
    【CF1139D】Steps to One
    【YbtOJ#20073】钻石守卫
    【YbtOJ#20072】相似子串
    【YbtOJ#20071】礼物购买
    【洛谷P4149】Race
    【洛谷P2059】卡牌游戏
    【CF140C】New Year Snowmen
    【GMOJ4282】平方数游戏
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/UOJ506.html
Copyright © 2011-2022 走看看