P16433 [APIO 2026 中国赛区] 上升
分享一个考场做法,但是因为一些原因场上只拿到了模数是质数的
第一次容斥
首先我们要求的是
这样我们只需要钦定
分析限制
首先令
这样整个排列
我们需要对
- 成立:那么需要满足
\boldsymbol{p_{l_i - 1}} < p_{l_i} < p_{l_i + 1} < \dots < p_{r_i} < \boldsymbol{p_{r_i + 1}} 。 - 不成立:此时
[l_i, r_i] 被分成了若干个区间[x_1, y_1], [x_2, y_2], \dots, [x_k, y_k](k \geq 2) ,其中[x_1, y_1] 和[x_k, y_k] 可以为空并且分别要和l_i - 1, r_i + 1 形成同一个上升段,而[x_2, y_2], [x_3, y_3], \dots, [x_{k - 1}, y_{k - 1}] 自己形成一个上升段。 -
-
设计一个 DP!
设
考虑
而对于条件不成立的情形,
处理 [x_1, y_1] 的限制
先考虑让
化简得到:
这样可以做到
处理 \dfrac{1}{k!} 的逆元问题
此时你发现当前乘上的所有的
于是这个题就做完了,复杂度
#include "ascend.h"
#include <bits/stdc++.h>
using namespace std;
long long infoC[580][580];
long long f[580][580], g[580][580], h[580][580], a[580], b[580], info[580], fac[580], mod;
int pre_good[580];
long long binomC(long long n, long long m) {
if (n < 0 || m < 0 || n < m) {
return 0;
}
return infoC[n][m];
}
int get_remainIdx(int x, int y, int z) {
return (pre_good[x] - (z - y));
}
long long dp[1 << 20][20], dp2[580][580];
int ascend(int c, int n, int m, vector<int> p, vector<int> w) {
mod = 1ll * m;
for (int i = 0; i <= 520; ++ i) {
for (int j = 0; j <= 520; ++ j) infoC[i][j] = 0;
}
infoC[0][0] = 1;
for (int i = 1; i <= 520; ++ i) {
infoC[i][0] = 1;
for (int j = 1; j <= i; ++ j) infoC[i][j] = (infoC[i - 1][j] + infoC[i - 1][j - 1]) % mod;
}
fac[0] = 1;
for (long long i = 1; i <= 510; ++ i) {
fac[i] = fac[i - 1] * i % mod;
}
a[1] = 1;
a[n + 2] = n + 2;
for (int i = 1; i <= n; ++ i) {
int x = p[i - 1];
if (x != 0) {
a[i + 1] = x + 1;
} else {
a[i + 1] = 0;
}
}
b[1] = 0;
b[n + 1] = 0;
for (int i = 2; i <= n; ++ i) {
b[i] = w[i - 2];
b[i] = (b[i] + mod - 1) % mod;
}
pre_good[0] = 0;
for (int i = 1; i <= n + 3; ++ i) {
pre_good[i] = pre_good[i - 1];
if (a[i] == 0) pre_good[i] ++;
}
for (int i = 0; i <= n + 3; ++ i) {
for (int j = 0; j <= n + 3; ++ j) {
f[i][j] = 0;
g[i][j] = 0;
h[i][j] = 0;
}
}
f[0][0] = 1;
int pos = 0, now_empty_num = 0;
for (int i = 2; i <= n + 1; ++ i) {
if (a[i] == 0 && a[i - 1] != 0) {
int cur_add = a[i - 1] - a[pos + 1] + 1;
int cur_len = (i - 1) - pos;
cur_add -= cur_len;
now_empty_num += cur_add;
int j = i;
while (a[j + 1] == 0 && j + 1 <= n + 2) ++ j;
for (int x = cur_add; x <= n + 3; ++ x) g[i - 1][x] = f[pos][x - cur_add];
for (int x = 0; x < cur_add; ++ x) g[i - 1][x] = 0;
if (a[j + 1] - a[i - 1] - 1 >= j - i + 1) {
long long cur_coef = binomC(a[j + 1] - a[i - 1] - 1, j - i + 1);
for (int x = i - 1; x <= j; ++ x) cur_coef = cur_coef * b[x] % mod;
int rem = (a[j + 1] - a[i - 1] - 1) - (j - i + 1);
for (int x = 0; x + rem <= n + 3; ++ x) {
if (g[i - 1][x] != 0) {
f[j][x + rem] = (f[j][x + rem] + g[i - 1][x] * cur_coef) % mod;
}
}
}
for (int x = i - 1; x <= j; ++ x) {
for (int y = x - (i - 1); y <= n + 3; ++ y) {
long long cur_coef = binomC(y, x - (i - 1));
if ((x - (i - 1)) % 2 == 1) cur_coef = (mod - cur_coef % mod) % mod;
h[x][y - (x - (i - 1))] = (h[x][y - (x - (i - 1))] + g[i - 1][y] * cur_coef) % mod;
}
}
for (int x = i - 1; x <= j; ++ x) {
for (int y = 0; y <= n + 3; ++ y) {
for (int z = max(i, z); z <= j; ++ z) {
if (h[x][y] == 0) continue;
g[z][y] = (g[z][y] + h[x][y] * binomC(get_remainIdx(z, y, now_empty_num), z - x)) % mod;
}
}
}
for (int x = i; x <= j; ++ x) {
long long cur_coef = 1;
for (int y = i - 1; y < x; ++ y) cur_coef = cur_coef * b[y] % mod;
for (int y = 0; y <= n + 3; ++ y) g[x][y] = g[x][y] * cur_coef % mod;
}
for (int x = i - 1; x <= j; ++ x) {
long long now_prod = 1;
for (int y = x + 1; y <= j; ++ y) {
if (y - 1 >= x + 1) {
now_prod = now_prod * b[y - 1] % mod;
}
int cnt_add = y - x;
for (int z = 0; z <= n + 3; ++ z) {
if (g[x][z] == 0) continue;
g[y][z] = (g[y][z] + g[x][z] * binomC(get_remainIdx(y, z, now_empty_num), cnt_add) % mod * now_prod) % mod;
}
}
}
int now_add = a[j + 1] - a[i - 1] - 1;
now_empty_num += now_add;
for (int x = i - 1; x <= j; ++ x) {
for (int y = n + 3; y >= now_add; -- y) {
g[x][y] = g[x][y - now_add];
}
for (int y = 0; y < now_add; ++ y) g[x][y] = 0;
}
for (int x = i - 1; x <= j; ++ x) {
long long now_prod = 1;
for (int y = x + 1; y <= j; ++ y) {
now_prod = now_prod * b[y] % mod;
}
int cnt_now = j - x;
for (int y = cnt_now; y <= n + 3; ++ y) {
f[j][y - cnt_now] = (f[j][y - cnt_now] + g[x][y] * binomC(y, cnt_now) % mod * now_prod) % mod;
}
}
pos = j;
}
}
int now_add = a[n + 2] - a[pos + 1] + 1;
int now_len = n + 2 - pos;
now_add -= now_len;
long long ans = 0;
for (int i = now_add; i <= n + 3; ++ i) {
ans = (ans + f[pos][i - now_add]) % mod;
}
for (int i = 1; i <= n + 1; ++ i) {
if (a[i] != 0 && a[i + 1] != 0) {
ans = ans * (b[i] + 1ll) % mod;
}
}
ans = (ans % mod + mod) % mod;
ans %= mod;
return ans;
}