P10008 [集训队互测 2022] Range Minimum Element
为方便表述,记
建立
不妨使用贪心构造
- 初始时将
a 中元素全部设置为+\infty 。 - 按权值从大到小遍历
b 。 - 遍历到
b_{[l,r]}=x 时,将对应的a 区间内的所有+\infty 设置为x 。- 若
a 的对应区间内并不存在+\infty (或已经设置过的x ),则代表这个b 并不存在于R(f) 中。
- 若
- 最后设置剩余的
+\infty 为1 。
根据这个过程,可以尝试去判断某一个确定的
- 考虑
a_x=1 的最小的x 。- 若不存在这样的
x ,则说明所有的b 都有b_i>1 ,且没有上述过程中『剩余的+\infty 』,也就是说条件为:所有b_i 的并集为[1,n] 。递归到『找最小a_x=2 』的子问题。 - 否则,对于完全被
[1,i-1] 包含的区间都有b_i>1 ,而包含了i 的区间都有b_i\leq 1 。并且有条件:完全被[1,i-1] 包含的区间的并集恰好为[1,i-1] (否则i 就不是最小的了)。递归到『找[1,i-1] 中最小a_x=2 』和 『找[1,n] 中次小a_x=1 (找[i+1,n] 中最小a_x=1 )』两个子问题。
- 若不存在这样的
普遍地,令
则转移为:
-
dp_{l,r,p}\leftarrow I_{l,r}\times dp_{l,r,p+1} -
dp_{l,r,p}\leftarrow I_{l,i-1}\times dp_{l,i-1,p+1}\times dp_{i+1,r,p}
此时复杂度为
由于 DP 的转移过程是简单加乘,故不难发现,
在对
复杂度
#define N 110
int n, m, K;
int l_[N * N], r_[N * N];
bool ok[N][N]; int d[N];
int dp[N][N][N << 1];
int val[N << 1];
void solve()
{
n = read(), m = read(), K = read();
for(int i = 1; i <= m; i++) l_[i] = read(), r_[i] = read();
for(int l = 1; l <= n; l++)
{
for(int r = l; r <= n; r++)
{
ok[l][r] = 1;
for(int i = l - 1; i <= r + 1; i++) d[i] = 0;
for(int i = 1; i <= m; i++) if(l <= l_[i] && r_[i] <= r) d[l_[i]]++, d[r_[i] + 1]--;
for(int i = l; i <= r; i++) d[i] += d[i - 1], !d[i] && (ok[l][r] = 0);
}
}
int tp = n + 5;
for(int x = 1; x <= tp; x++)
{
for(int len = 1; len <= n; len++)
{
for(int l = 1, r = len; r <= n; l++, r++)
{
if(ok[l][r]) dp[l][r][x] = dp[l][r][x - 1];
if(l == r) plus_(dp[l][r][x], 1);
else plus_(dp[l][r][x], dp[l + 1][r][x]);
if(l != r && ok[l][r - 1]) plus_(dp[l][r][x], dp[l][r - 1][x - 1]);
for(int i = l + 1; i < r; i++)
if(ok[l][i - 1])
plus_(dp[l][r][x], 1ll * dp[l][i - 1][x - 1] * dp[i + 1][r][x] % mod);
}
}
val[x] = dp[1][n][x];
}
if(K <= tp) { printf("%d\n", val[K]); return; }
int ans = 0;
for(int i = 1; i <= tp; i++)
{
int now = val[i];
for(int j = 1; j <= tp; j++)
if(i != j)
mul_(now, sm(K + mod - j)), mul_(now, ksm(sm(i + mod - j), mod - 2));
plus_(ans, now);
}
print(ans, '\n');
}