题解:AT_arc104_f [ARC104F] Visibility Sequence

posted on 2024-08-03 14:02:17 | under | source

感觉没必要硬套笛卡尔树,反而使问题复杂化了。不过思路还是相似的,考虑最大值分治。

这是有效的,因为最大值在不同位置 \(pos\) 时,\(P\) 显然不同:考虑 \(pos_1<pos_2\) 分别是最大值时,对于前者,\(pos_2\) 必然向 \([pos_1,pos_2-1]\) 有边;对于后者,\(pos_2\) 不可能向 \([1,pos_2-1]\) 有边。两两不同,不重不漏。

注意一下,本题可能有重复元素,所以“最大值”定义为相同的情况尽量向右取,否则上面讨论不成立。

转移十分容易,考虑 \(f_{l,r,H}\) 表示区间 \([l,r]\),值域在 \([1,H]\) 时的方案数,枚举最大值位置 \(l\le pos\le r\),那么此时新值域为 \(H_2=\min(H,x_{pos})\),有 \(f_{l,pos-1,H_2}\times f_{pos+1,r,H_2-1}\)

注意到 \(x\) 很大,不妨离散化一下,实际上,对 \(n\)\(\min\) 即可。

记忆化搜索实现,注意一下边界处理,复杂度 \(O(n^4)\)

代码

#include<bits/stdc++.h>
using namespace std;

#define int long long
#define ADD(a, b) a = (a + b) % mod
const int N = 1e2 + 5, mod = 1e9 + 7;
int n, x[N], mx;
int f[N][N][N], vis[N][N][N];

inline int dfs(int l, int r, int H){
	if(l > r) return 1;
	if(H < 1) return 0;
	if(vis[l][r][H]) return f[l][r][H];
	vis[l][r][H] = 1;
	for(int pos = l; pos <= r; ++pos){
		int H2 = min(x[pos], H);
		ADD(f[l][r][H], dfs(l, pos - 1, H2) * dfs(pos + 1, r, H2 - 1) % mod);
	}
	return f[l][r][H];
}
signed main(){
	cin >> n;
	for(int i = 1; i <= n; ++i) scanf("%lld", &x[i]), x[i] = min(x[i], n), mx = max(mx, x[i]);
	cout << dfs(1, n, mx);
	return 0;
}
posted @ 2026-01-15 08:14  Zwi  阅读(4)  评论(0)    收藏  举报