P7213 最古の遺跡 3 题解-dp 好题

P7213 最古の遺跡 3

见到两次了,但是第二次忘了,遂随手题解一篇。

原,太原了!但也忘了

题目描述

你有 \(2N\) 个柱子,每个柱子各有一个高度,且对于 $ 1 \le k \le N $,各有两根柱子的高度为 \(k\)。现在,发生了 \(N\) 次地震,每次地震会使一些石柱的高度 \(-1\),其他石柱高度不变。

  • 石柱 \(i\) 地震时高度不变,当且仅当 \(h_i\ge 1\) 并且对于 \(j>i\) 都要有 \(h_i\not=h_j\)

\(N\) 次地震后,恰好只剩下了 \(N\) 个石柱。仅存的 \(N\) 个石柱的位置分别是 \(A_1,A_2,\ldots,A_N\),问最初 \(2N\) 个石柱高度的修建方案数 \(\bmod~10^9+7\) 的值。

$ n\le 600$,时间 4s

分析

注意到,可以考虑从后往前震柱子。如果后面有所有的 $ 1\sim h $ 柱子,那么前面的 $ <h $ 的柱子全部木大。以此 dp $ f_{i,j} $ 表示考虑到后 \(i\) 个,其中 $ 1 \sim j$ 都有。

定义前面有 \(c_0\) 个柱子被震没了(不含自身),有 \(c_1\) 个柱子还在(称之为标准柱),那么分类讨论转移:

  • 如果 \(i\) 震没了,合计 \(2j\) 种可能,标准柱用了 \(j\),其他震没柱用了 \(c_0\),则 $ f_{i,j} \leftarrow (j-c_0)f_{i+1,j} $.
  • 如果 \(i\) 还在,那么分讨其震完后是否为 $ j+1 $:
    • 若不是,则不管他,$ f_{i,j} \leftarrow f_{i+1,j} $;
    • 否则,考虑有了 \(j+1\),能否将之前的一些柱子连起来。枚举连了 \(k\) 个柱子(包括自己),接下来分析系数:首先,标准柱本身的高度可能为 $ k-1 $ 种可能;其次,从前面任选一些标准柱作为 $j+2\sim k $,系数为 $\binom{c_1-j}{k-1} $;以及,那些柱子之间的顺序,称之为 \(g_k\).

接下来分析 \(g\)。不难想到 \(g_i\) 的组合意义是“有 \(i\) 个柱子没有被震没,且最后分别为 $ 1 \sim i $ 的方案数”。直接枚举最前一个柱子的高度 \(j\),将整个高度序列分成 \(j-1\)\(j-i\) 两半,自己有 \(j+1\) 种选法,最后式子为 $g_i=\sum_{j\le i} \binom{i-1}{j-1} \times g_{j-1} \times g_{i-j} \times (j+1) $

综上,做完啦!复杂度 $ O(n^3) $

代码

void mian()
{
	read(n);m=n*2;
	for(int i=1;i<=n;i++)
	{
		int x;read(x);
		c[x]=1;
	}
	g[0]=1;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=i;j++)
		{
			modadd(g[i],1ll*g[j-1]*g[i-j]%Mod*C(i-1,j-1)%Mod*(j+1)%Mod);
		}
	}
	int c0=0,c1=0;
	f[m+1][0]=1;
	for(int i=m;i;i--)
	{
		if(c[i]==0)
		{
			for(int j=c0;j<=n;j++)
			{
				f[i][j]=1ll*f[i+1][j]*(j-c0)%Mod;
			}
			c0++;
			continue;
		}
		for(int j=0;j<=c1+1;j++)
		{
			f[i][j]=f[i+1][j];
			for(int k=0;k<j;k++)
			{
				modadd(f[i][j],1ll*f[i+1][k]*C(c1-k,j-k-1)%Mod*(j-k+1)%Mod*g[j-k-1]%Mod);
			}
		}
		c1++;
	}
	int res=f[1][n];
	modmul(res,ksm(inv(2),n));
	cout<<res;
}

参考资料

1

posted @ 2026-07-10 15:02  FarrisL  阅读(5)  评论(0)    收藏  举报