题解: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;
}

浙公网安备 33010602011771号