设 \(f_{i, j, k}\) 表示从 \(i\) 往前,第一个与 \(a_i\) 颜色不同的位置是 \(j\),第一个颜色与 \(a_i, a_j\) 都不相同的位置是 \(k\) 的方案数,其中某个值为 \(0\) 表示这个位置不存在。当然 \(i\gt j\gt k\)(特别地,当 \(j=0\) 时 \(k\) 可以为 \(0\))
如果我们有一个形如 \((l,r,x)\) 的限制,那么这样的三元组 \((i,j,k)(r=i)\) 是不符合限制的(即 \(f_{i,j,k}\) 需要设为 \(0\)):
-
\(x=1\) 且 \(l \le j\),因为 \([l,r]\) 这段区间内出现了一个与 \(a_i\) 不同的 \(a_j\)。
-
\(x=2\) 且 \(l \le k\) 或 \(j\lt l\),前者是因为出现了第三种既不同于 \(a_i\) 也不同于 \(a_j\) 的颜色,后者是因为距离 \(i\) 最近的不同于 \(a_i\) 的 \(a_j\) 并不在 \([l,r]\) 内,即 \([l,r]\) 这段区间内只有一个颜色。
-
\(x=3\) 且 \(k\lt l\),因为距离 \(i\) 最近的第三种不同的颜色 \(a_k\) 在 \([l,r]\) 之外,即 \([l,r]\) 内至多只有两种颜色。
所以用 \(n\) 个 vector
来保存限制,每次到一个位置把以它为右端点的限制取出然后剔除不合法的状态。
考虑从 \(i\) 转移 到 \(i+1\):
- 若 \(a_{i+1}=a_i\),则 \(f_{i+1,j,k}\gets f_{i+1,j,k}+f_{i,j,k}\)。
- 若 \(a_{i+1}=a_j\),则 \(f_{i+1,i,k}\gets f_{i+1,i,k}+f_{i,j,k}\)。
- 若 \(a_{i+1}=a_k\),则 \(f_{i+1,i,j}\gets f_{i+1,i,j}+f_{i,j,k}\)。
初值为 \(f_{1,0,0}=3\),因为这里的 DP 只考虑颜色相对之间的关系,而 \(a_1\) 有三种选法,确定了 \(a_1\) 之后,所有合法的方案都被不重不漏的划分了。
最终答案就是所有 \(f_{n,j,k}\) 的和,其中 \(j\lt n,k\lt\max(1,j)\)。
时间复杂度 \(\mathcal O(n^3)\)。
Code:
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
typedef pair <int, int> pii;
typedef long long ll;
const int N = 305, mod = 1e9 + 7;
int n, m;
vector <pii> vec[N];
int f[N][N][N];
void add(int &a, int b) {
a += b;
if (a >= mod) a -= mod;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1, l, r, cnt; i <= m; ++i) scanf("%d%d%d", &l, &r, &cnt), vec[r].emplace_back(l, cnt);
f[1][0][0] = 3;
for (int i = 0; i <= n; ++i) {
for (auto it : vec[i]) {
int l = it.fi, cnt = it.se;
for (int j = 0; j < i; ++j) {
int lim = j ? j - 1 : 0;
for (int k = 0; k <= lim; ++k) {
if (cnt == 1 && l <= j) f[i][j][k] = 0;
if (cnt == 2 && (l <= k || j < l)) f[i][j][k] = 0;
if (cnt == 3 && k < l) f[i][j][k] = 0;
}
}
}
if (i == n) break;
for (int j = 0; j < i; ++j) {
int lim = j ? j - 1 : 0;
for (int k = 0; k <= lim; ++k) {
if (!f[i][j][k]) continue;
add(f[i + 1][j][k], f[i][j][k]), add(f[i + 1][i][k], f[i][j][k]), add(f[i + 1][i][j], f[i][j][k]);
}
}
}
int ans = 0;
for (int j = 0; j < n; ++j) {
int lim = j ? j - 1 : 0;
for (int k = 0; k <= lim; ++k)
add(ans, f[n][j][k]);
}
printf("%d", ans);
return 0;
}
标签:gt,颜色,int,ARC074E,lt,gets,mod
From: https://www.cnblogs.com/Kobe303/p/16862962.html