cancan123456
2024-11-18 09:51:31
这一场先过了 B 再过了 A /fendou
性质 1:一个连通分量内点的编号连续。
证明:反证法,设
所以我们知道
性质 2:
左推右:反证法,若
右推左:反证法,取
现在我们枚举
时间复杂度为
#include <cstdio>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
const int N = 2005;
ll f[N][N], suf[N][N], pow[N][N];
int b[N], suf_max[N], suf_cnt[N];
int max(int a, int b) {
return a > b ? a : b;
}
int main() {
// freopen("in.txt", "r", stdin);
int n, m;
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", &b[i]);
}
for (int i = n; i >= 1; i--) {
suf_max[i] = max(suf_max[i + 1], b[i]);
suf_cnt[i] = suf_cnt[i + 1];
if (b[i] == -1) {
suf_cnt[i]++;
}
}
for (int i = 0; i <= m; i++) {
pow[i][0] = 1;
for (int j = 1; j <= n; j++) {
pow[i][j] = pow[i][j - 1] * i % mod;
}
}
f[0][m] = 1;
for (int i = 1; i <= n; i++) {
for (int j = m; j >= 1; j--) {
suf[i - 1][j] = (suf[i - 1][j + 1] + f[i - 1][j]) % mod;
}
if (b[i] == -1) {
for (int j = 1; j <= m; j++) {
f[i][j] = (suf[i - 1][j] + f[i - 1][j] * (m - j)) % mod;
}
} else {
for (int j = 1; j < b[i]; j++) {
f[i][j] = f[i - 1][j];
}
for (int j = b[i]; j <= m; j++) {
f[i][b[i]] = (f[i][b[i]] + f[i - 1][j]) % mod;
}
}
}
ll ans = 0;
for (int i = 1; i < n; i++) {
for (int j = suf_max[i + 1] + 1; j <= m; j++) {
ans = (ans + pow[j - 1][suf_cnt[i + 1]] * f[i][j]) % mod;
}
}
ll add = 1;
for (int i = 1; i <= n; i++) {
if (b[i] == -1) {
add = add * m % mod;
}
}
printf("%lld", (ans + add) % mod);
return 0;
}