一道有点难想的 dp。
记 (dp_{i,j,k}) 表示第 (i) 个位置,与当前位置颜色不同的球最后出现的位置为 (j),与这两种颜色都不同的球最后出现的位置为 (k) 的方案数。
转移分成三种:
-
第 (i+1) 个位置的颜色与第 (i) 个位置的颜色相同,从 (dp_{i,j,k}) 转移到 (dp_{i+1,j,k})
-
第 (i+1) 个位置的颜色与第 (j) 个位置的颜色相同,从 (dp_{i,j,k}) 转移到 (dp_{i+1,i,k})
-
第 (i+1) 个位置的颜色与第 (k) 个位置的颜色相同,从 (dp_{i,j,k})转移到 (dp_{i+1,i,j})
那么给出的 (m) 条限制,如果 (x=3),我们让后两维都 (ge l)。如果 (x=2) ,我们让后两维中大的那个 (ge l),小的那个 (leq l)。如果 (x=1),我们让后两维都 (leq l)就好了。
#include <bits/stdc++.h>
#define reg register
#define ll long long
using namespace std;
const int MAXN = 310;
const int mod = 1e9 + 7;
int n, m, dp[MAXN][MAXN][MAXN];
struct lim {
int l, x;
};
vector<lim> vec[MAXN];
bool check(int l, int r, int x) {
return l <= x && x < r;
}
inline void work() {
scanf("%d%d", &n, &m);
for(reg int i = 1; i <= m; ++i) {
int l, r, x;
scanf("%d%d%d", &l, &r, &x), vec[r].push_back((lim) { l, x });
}
dp[0][0][0] = 1;
for(reg int i = 1; i <= n; ++i) {
int la = 0, ra = i, lb = 0, rb = i;
for(auto it : vec[i]) {
int tmp = it.l;
if(it.x == 1) ra = min(ra, tmp), rb = min(rb, tmp);
if(it.x == 2) rb = min(rb, tmp), la = max(la, tmp);
if(it.x == 3) la = max(la, tmp), lb = max(lb, tmp);
}
for(reg int j = 0; j < i; ++j) for(reg int k = 0; k < j || !k; ++k) {
int tmp = dp[i - 1][j][k], c = i - 1;
if(check(la, ra, j) && check(lb, rb, k)) dp[i][j][k] = (dp[i][j][k] + tmp) % mod;
if(check(la, ra, c) && check(lb, rb, j)) dp[i][c][j] = (dp[i][c][j] + tmp) % mod;
if(check(la, ra, c) && check(lb, rb, k)) dp[i][c][k] = (dp[i][c][k] + tmp) % mod;
}
}
int ans = 0;
for(reg int i = 0; i <= n; ++i) for(reg int j = 0; j <= n; ++j) ans = (ans + dp[n][i][j]) % mod;
printf("%d
", ans);
}
int main() {
int _ = 1;
// scanf("%d", &_);
while(_--) work();
return 0;
}