發現一個序列 \(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];
}