Gushing over Pr|

BigSmall_En

园龄:3年2个月粉丝:3关注:5

2022-11-21 16:29阅读: 18评论: 0推荐: 0

ARC104F Visibility Sequence 题解

[ARC104F] Visibility Sequence

给一个长为 \(n\) 的数列 \(h_{1\dots n}\),第 \(i\) 项在 \([1,h_i]\) 中选一个数,得到数列 \(x_{1\dots n}\)

再构造一个数列 \(p_{1\dots n}\)\(p_i=\max j(j<i,x_j>x_i)\),若不存在这样的 \(j\)\(p_i=-1\)

求能构造出多少种 \(p\)

\(n\leq 100,h_i\leq 10^5\)

显然 \(h_i\) 可以很大,但是大于 \(n\) 的时候是没有意义的,因为我们只需要看 \(x\) 的相对大小。所以可以对 \(n\)\(\min\)(因为算上 \(-1\) 之后至多有 \(n+1\) 个不同的值,为 \(h_i=n\) 的时候就已经能够保证这些值全部被取到)。

考虑 \(i\)\(p_i\) 之间之间连边,如果 \(p_i=-1\) 不妨将其视作一个编号为 \(0\) 的点。容易发现构成了一颗树。将 \(0\) 号点视为树根,发现这棵树具有以下性质性质。

  • 子树根的编号最小且 \(x\) 值大于其子树内所有点的 \(x\) 值,根据定义可以得到。
  • 子树内点的标号连续,即不能出现 \(i<j<k<l\)\(p_k=i,p_l=j\) 的情况,容易发现 \(p_k=i\) 说明 \(x_i>x_k>x_j\),而 \(p_l=j\) 说明了 \(x_j>x_l>x_k\),两者矛盾。
  • 子树内深度相同的节点(即兄弟节点)中,编号越大的节点 \(x\) 值越大(否则这些节点之间就会连边了)。

于是我们定义 \(f_{l,r,k}\) 为区间 \([l,r]\) 构成一颗以 \(l\) 为根的树且 \(h_l=k\) 的方案数,定义 $g_{l,r,k} $ 为期间 \([l,r]\) 构成了一个最大的数为 \(k\) 的森林的方案数。同时定义 \(sf\)\(sg\)\(f,g\) 第三维的前缀和。得到转移:

\[\begin{aligned} f_{l,r,k}&\gets g_{l+1,r,k-1} \quad k\leq h_l\\ g_{l,r,k}&\gets f_{l,r,k}\quad k\leq h_l\\ g_{l,r,k}&\gets g_{l,r,k} +\sum_{i=l}^{r-1} sg_{l,i,k}\times f_{i+1,r,k} \quad k\leq h_{i+1}\\ g_{l,r,k}&\gets g_{l,i,k} +\sum_{i=1}^{r-1}g_{l,i,k}\times sf_{i+1,r,k-1}\quad k\leq h_{i+1} \end{aligned} \]

第一个和第二个式子表示 \(l\) 节点作为区间 \([l,r]\) 的树根。

第三个式子 \(f_{i+1,r,k}\) 保证了森林中至少有一个点为 \(x=k\),同时也保证了不会算重。

第四个式子 \(sf_{i+1,r,k-1}\)\(k-1\) 是为了保证第三条性质。

初始状态 \(f_{i,i,1}=g_{i,i,1}=1\),答案状态 \(sg_{1,n,n}\)

具体实现见代码。

using namespace modulo;
using namespace FastIO;

int n,h[N];
ll f[N][N][N],g[N][N][N],sf[N][N][N],sg[N][N][N];
int main(){
	n=read();
	for(int i=1;i<=n;++i){
		h[i]=read();
		h[i]=min(h[i],n);
	}
	for(int i=1;i<=n;++i){
		f[i][i][1]=g[i][i][1]=1;
		for(int j=1;j<=n;++j)
			sf[i][i][j]=sg[i][i][j]=1;
	}
	for(int len=2;len<=n;++len){
		for(int l=1,r=len;r<=n;++l,++r){
			for(int k=1;k<=h[l];++k)
				f[l][r][k]=g[l][r][k]=g[l+1][r][k-1];
			for(int i=l;i<r;++i){
				for(int k=1;k<=h[i+1];++k){
					g[l][r][k]=add(g[l][r][k],mul(sg[l][i][k],f[i+1][r][k]));
					g[l][r][k]=add(g[l][r][k],mul(g[l][i][k],sf[i+1][r][k-1]));
				}
			}
			for(int i=1;i<=n;++i){
				sf[l][r][i]=add(sf[l][r][i-1],f[l][r][i]);
				sg[l][r][i]=add(sg[l][r][i-1],g[l][r][i]);
			}
		}
	}
	printf("%lld\n",sg[1][n][n]);
	return 0;
}

后记

写得很烂。

同时感谢这篇题解对我的启发。

本文作者:BigSmall_En

本文链接:https://www.cnblogs.com/BigSmall-En/p/16911832.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   BigSmall_En  阅读(18)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起