题意
给定一个长为 \(n\) 的序列,\(a_i \in [1, m]\) 对于所有 \(1 \le i < j \le n\) 且 \(a_i \le a_j\) 则对 \((i, j)\) 连无向边。
求对于给定序列 \(b\) 所有的 -1
替换为 \([1, m]\) 的所有情况所连成的图连通块个数之和。
\(n, m \le 2000\)。
Sol
唐完了。
首先注意到连通块都是区间,不会证。
所以显然只需要考虑每个相邻的两个点没有边时连通块增加的贡献即可。
考虑 \((i, i + 1)\) 什么情况下没有边,注意到当前当且仅当: \(\min_{l = 1} ^ {i - 1} > \max_{l = i + 1} ^ n\)。
然后你直接枚举分界点,枚举前面一段的最小值,剩下的直接组合算出来就做完了。
复杂度:\(O(n m \log)\)。
Code
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <array>
using namespace std;
#ifdef ONLINE_JUDGE#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 23], *p1 = buf, *p2 = buf, ubuf[1 << 23], *u = ubuf;#endif
int read() {int p = 0, flg = 1;char c = getchar();while (c < '0' || c > '9') {if (c == '-') flg = -1;c = getchar();}while (c >= '0' && c <= '9') {p = p * 10 + c - '0';c = getchar();}return p * flg;
}
void write(int x) {if (x < 0) {x = -x;putchar('-');}if (x > 9) {write(x / 10);}putchar(x % 10 + '0');
}
bool _stmer;const int N = 2e3 + 5, mod = 998244353;int pow_(int x, int k) {int ans = 1;while (k) {if (k & 1) ans = 1ll * ans * x % mod;x = 1ll * x * x % mod;k >>= 1;}return ans;
}void Mod(int &x) {if (x >= mod) x -= mod;if (x < 0) x += mod;
}array <int, N> s, pre, suf, isl;bool _edmer;
int main() {cerr << (&_stmer - &_edmer) / 1024.0 / 1024.0 << "MB\n";int n = read(), m = read();pre[0] = 2e9;for (int i = 1; i <= n; i++) {s[i] = read(), isl[i] = isl[i - 1];if (~s[i]) pre[i] = min(pre[i - 1], s[i]);else pre[i] = pre[i - 1], isl[i]++;}for (int i = n; i; i--)suf[i] = max(suf[i + 1], s[i]);int ans = 0;for (int i = 1; i <= n; i++) {if (pre[i] <= suf[i + 1])continue;for (int j = suf[i + 1] + 1; j <= min(pre[i], m); j++) {if (j == pre[i])ans += 1ll * pow_(m - j + 1, isl[i]) * pow_(j - 1, isl[n] - isl[i]) % mod, Mod(ans);else if (isl[i])ans += 1ll * (pow_(m - j + 1, isl[i]) - pow_(m - j, isl[i]) + mod) % mod * pow_(j - 1, isl[n] - isl[i]) % mod, Mod(ans);}}write(ans), puts("");return 0;
}