发现一个序列 \(x\) 不止可以用一个 \(p\) 得到,肯定不能直接计数,考虑构造一个映射。
假如已经定下了 \(x\),我们通过一种固定的操作得到 \(p\),这样就能改为统计可以由操作得到的 \(p\) 的数量,他们同样唯一对应一个 \(x\)。
我们考虑枚举从 \(n\) 到 \(1\) 去枚举 \(v\),对每个 \(v\) 找到一个能找到的最左边的点赋值。一个位置 \(pos\) 能赋值 \(v\) 当且仅当所有 \(l_i,r_i\) 包含 \(pos\) 的 \(x_i\) 等于 \(pos\)。
接下来我们就可以处理左区间和右区间的位置了。容易发现其右边的值都要小于左边的值,这将变成两个子问题。
现在 \(x\) 并不固定,我们需要分析条件才能计数。
注意到,若当前我们在 \(pos\) 这里赋值,那么对于左侧的最大值的位置 \(k\),一定存在一个区间满足 \(l_i\le k\le pos\le r_i\),因为若没有区间同时包含 \(k,pos\),那么显然我可以让 \(p_{pos}=v\),所以一定存在这样的区间。之所以存在这种情况那只能是因为这个区间的 \(x_i\) 等于 \(pos\)。我们需要用一个大数在这里填,填完以后再将区间删去才能更新 \(k\)。
这启发我们进行一个区间 dp,设 \(f_{l,r,i}\) 表示在区间 \(l,r\) 中最大值位置在 \(i\) 的方案数。但是由于这样子复杂度很劣,我们将状态改为在区间 \(l,r\) 中最大值位置大于等于 \(i\) 的方案数就能 \(\mathcal{O}(n^3)\) 解决问题了,具体就是先维护区间如果要选 \(pos\) 赋值,包含 \(pos\) 的区间的最小 \(l_i\),然后再后缀和转移即可。
代码:
#include <bits/stdc++.h>
#define int long long
#define rep(i, l, r) for (int i = l; i <= r; ++ i)
#define rrp(i, l, r) for (int i = r; i >= l; -- i)
#define pii pair <int, int>
#define eb emplace_back
#define id(x, y) n * (x - 1) + y
#define ls p << 1
#define rs ls | 1
using namespace std;
constexpr int N = 300 + 5, M = (1ll << 31) - 1, P = 998244353;
constexpr double PI = acos (-1.0);
inline int rd () {
int x = 0, f = 1;
char ch = getchar ();
while (! isdigit (ch)) {
if (ch == '-') f = -1;
ch = getchar ();
}
while (isdigit (ch)) {
x = (x << 1) + (x << 3) + ch - 48;
ch = getchar ();
}
return x * f;
}
int qpow (int x, int y) {
int ret = 1;
for (; y; y >>= 1, x = x * x % P) if (y & 1) ret = ret * x % P;
return ret;
}
int f[N][N][N], g[N][N][N];
int n, m;
long long fac[N], ifac[N];
int C (int n, int m) {
if (m < 0 || m > n) return 0;
return fac[n] * ifac[m] % P * ifac[n - m] % P;
}
int l[N * N], r[N * N];
signed main () {
// freopen ("1.in", "r", stdin);
// freopen ("1.out", "w", stdout);
n = rd (), m = rd ();
rep (i, 1, m) l[i] = rd (), r[i] = rd ();
rep (i, 0, n + 1) rep (j, 0, n + 1) rep (k, 0, n + 1) g[i][j][k] = n + 1;
rep (i, 1, m) {
rep (j, l[i], r[i]) {
g[l[i]][r[i]][j] = min (g[l[i]][r[i]][j], l[i]);
}
}
rep (len, 1, n) {
rep (l, 1, n - len + 1) {
int r = l + len - 1;
rep (k, 1, n) g[l][r][k] = min (g[l][r][k], min (g[l + 1][r][k], g[l][r - 1][k]));
}
}
rep (l, 1, n + 1) rep (k, 1, n + 1) f[l][l - 1][k] = 1;
rep (len, 1, n) {
rep (l, 1, n - len + 1) {
int r = l + len - 1;
rrp (k, l, r) {
(f[l][r][k] += f[l][r][k + 1] + f[l][k - 1][g[l][r][k]] * f[k + 1][r][k + 1]) %= P;
}
}
} cout << f[1][n][1];
}
标签:Argmax,rep,pos,len,int,Range,AGC056B,区间,define
From: https://www.cnblogs.com/lalaouyehome/p/18446270