Loading

AGC067B 做题记录

link

考虑时光倒流,相当于每次选择一个区间,若未覆盖的位置的颜色都相同,则把区间里的所有位置覆盖,一个序列合法当且仅当经过若干次覆盖后 \([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;
}
posted @ 2024-09-25 11:40  Lgx_Q  阅读(10)  评论(0编辑  收藏  举报