AGC067B 做题记录
考虑时光倒流,相当于每次选择一个区间,若未覆盖的位置的颜色都相同,则把区间里的所有位置覆盖,一个序列合法当且仅当经过若干次覆盖后 \([1,n]\) 中所有位置都被覆盖。
容斥,考虑经过若干次覆盖后,还剩未覆盖位置集合 \(S\),满足不存在可以继续覆盖 \(S\) 中的位置的区间。
\(S\) 把原序列分成了若干个区间,发现每个子区间的问题是独立的,可以设 \(dp[l, r]\) 表示通过 \([l, r]\) 内的区间,最终可以将 \([l, r]\) 所有位置覆盖的合法序列数量。
那么对于一个固定的 \(S\) 来说,我们可以计算它的额外系数,为若干个子区间的 \(dp[l, r]\) 乘积。现在的问题是,如何判定一个 \(S\) 集合中对应位置的染色方案是否合法。
对于极大的未被覆盖的同色段 \([p, q]\),不存在 \([p, q]\) 内的区间,包含 \(S\) 中任意一个位置。考虑跳跃式决策的 DP:设 \(f[l, r, i]\) 表示对于子区间 \([l, r]\),且 \(r, i\in S\),其中 \(i\) 是上一个未被覆盖的位置的颜色与 \(r\) 的颜色不同的位置。
考虑转移,枚举 \(p\),考虑 \(f[l, i, p]\) 对 \(f[l, r, \_]\) 的贡献:
-
若位置 \(r\) 的颜色与 \(i\) 相同,并且 \([p + 1, r - 1]\) 内不存在区间可以覆盖位置 \(i\):\(f[l, r, p] \gets f[l, i, p]\)
-
若位置 \(r\) 的颜色与 \(i\) 不同,并且 \([p + 1, r - 1]\) 内不存在区间可以覆盖位置 \(i\):\(f[l, r, i] \gets f[l, i, p]\cdot (C - 1)\)
最终不合法的方案数为 \(\sum\limits_i \sum\limits_j [[j + 1, r] \text{ 内不存在区间可以覆盖位置 }i]f[l, i, j]\)。
点击查看代码
#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define mkp make_pair
#define pir pair <ll, ll>
#define pb emplace_back
#define i128 __int128
using namespace std;
const ll maxn = 110, mod = 998244353;
ll n, m, c, ok[maxn][maxn][maxn];
ll dp[maxn][maxn], f[maxn][maxn][maxn];
void add(ll &x, const ll y) { x = x + y >= mod? x + y - mod : x + y; }
int main() {
scanf("%lld%lld%lld", &n, &m, &c);
for(ll i = 1; i <= m; i++) {
ll l, r; scanf("%lld%lld", &l, &r);
for(ll j = l; j <= r; j++)
ok[l][r][j] = 1;
}
for(ll l = n; l; l--)
for(ll r = l; r <= n; r++)
for(ll i = l; i <= r; i++)
ok[l][r][i] |= ok[l + 1][r][i] | ok[l][r - 1][i];
for(ll i = 1; i <= n + 1; i++)
dp[i][i - 1] = 1;
for(ll l = n; l; l--) {
for(ll r = l, prod = c; r <= n; r++, prod = prod * c %mod) {
f[l][r][l - 1] = dp[l][r - 1] * c %mod;
for(ll i = l; i < r; i++) {
for(ll j = l - 1; j < i; j++) {
if(!ok[j + 1][r - 1][i]) {
add(f[l][r][i], f[l][i][j] * (c - 1)
%mod * dp[i + 1][r - 1] %mod);
add(f[l][r][j], f[l][i][j] *
dp[i + 1][r - 1] %mod);
}
}
} ll ret = 0;
for(ll i = l; i <= r; i++)
for(ll j = l - 1; j < r; j++)
if(!ok[j + 1][r][i])
add(ret, f[l][i][j] * dp[i + 1][r] %mod);
dp[l][r] = (prod - ret + mod) %mod;
}
} printf("%lld", dp[1][n]);
return 0;
}