题解:P16433 [APIO 2026 中国赛区] 上升
考虑容斥,选定若干个上升连续段,令段内都是递增排列的,然后对实际上是
考虑划分出来的连续段,有几种情况:
-
-
- 我们记录:$nxt_i$ 表示 $i$ 右边第一个 $p_j \not = 0$ 的位置 $j$,$lst_i$ 表示 $i$ 左边第一个 $p_j \not = 0$ 的位置 $j$。 - 对于 $j < nxt_l$ 的位置 $j$,只能填写 $q_j < p_{nxt_l}$; - 对于 $j > lst_r$ 的位置 $j$,只能填写 $q_j > p_{lst_r}$; - 否则,只能填写 $q_j \in (p_{lst_j}, p_{nxt_j})$。
考虑提前钦定 trick,对于一个位置
为了方便,我们分步转移,设置辅助数组
最后一步看起来是瓶颈,但是实际上,可以另设
// Think TWICE, code ONCE
#include <bits/stdc++.h>
#define ll long long
using namespace std;
namespace qwq {
const int N = 505;
int n, ans, Mod, p[N], w[N], nxt[N], pre[N];
int f[N][N], g[N][N], h[N][N], C[N][N], mul[N][N];
inline void Add(int &x, int y) { x += y; if(x >= Mod) x -= Mod; }
void Solve() {
int i, j, k, t;
memset(f, 0, sizeof(f)), memset(g, 0, sizeof(g)), memset(h, 0, sizeof(h)), f[0][0] = 1;
w[n++] = 1, p[n] = n;
for(i = 1; i < n; i++) w[i] = (w[i] + Mod - 1) % Mod;
for(i = 1; i <= n; i++) {
mul[i][i] = 1;
for(j = i + 1; j <= n; j++) mul[i][j] = 1ll * mul[i][j - 1] * w[j - 1] % Mod;
}
for(i = 0; i <= n; i++) {
C[i][0] = 1;
for(j = 1; j <= i; j++) C[i][j] = C[i - 1][j], Add(C[i][j], C[i - 1][j - 1]);
}
for(i = 1, pre[0] = 0; i <= n; i++) pre[i] = p[i] ? i : pre[i - 1];
for(i = n, nxt[n + 1] = n + 1; i >= 0; i--) nxt[i] = p[i] ? i : nxt[i + 1];
for(i = 0; i <= n; i++) for(j = 0; j <= i; j++) {
int rem = p[pre[i]] - i + j;
if(rem < 0) continue;
if(nxt[i] == i && g[i][j]) {
int val = 1ll * g[i][j] * mul[i][nxt[i + 1]] % Mod;
for(t = 0; t <= j; t++) {
int x = p[nxt[i + 1]] - p[i] - 1, y = nxt[i + 1] - i - 1, z = j - t;
if(x >= y) Add(g[nxt[i + 1]][t], 1ll * val * C[x][y] % Mod * C[x - y][z] % Mod);
}
for(k = i; k < nxt[i + 1]; k++) {
Add(f[k][j + k - i], 1ll * g[i][j] * C[j + k - i][j] % Mod * mul[i][k] % Mod);
}
}
for(k = i; k < nxt[i + 1]; k++) {
Add(f[k][j + k - i], 1ll * h[i][j] * C[j + k - i][j] % Mod * mul[i][k] % Mod);
}
if(f[i][j]) {
for(k = i + 1; k < nxt[i + 1]; k++) {
int val = 1ll * f[i][j] * mul[i + 1][k] % Mod;
Add(h[k][j], 1ll * val * C[rem][k - i] % Mod);
Add(f[k][j + k - i], 1ll * val * C[j + k - i][j] % Mod);
}
if(i < n) {
int val = 1ll * f[i][j] * mul[i + 1][nxt[i + 1]] % Mod;
for(t = 0; t <= j + nxt[i + 1] - i - 1; t++) {
Add(g[nxt[i + 1]][t], 1ll * val * C[p[nxt[i + 1]] - p[pre[i]] - 1][j - t] % Mod * C[rem + p[nxt[i + 1]] - p[pre[i]] - 1 - (j - t)][nxt[i + 1] - 1 - i] % Mod);
}
}
}
}
ans = f[n][0];
}
}
int ascend(int c, int n, int m, vector<int> p, vector<int> w) {
int i; qwq::n = n, qwq::Mod = m;
for(i = 1; i <= n; i++) qwq::p[i] = p[i - 1];
for(i = 1; i < n; i++) qwq::w[i] = w[i - 1];
qwq::Solve(); return qwq::ans;
}
::::