[ARC074C] RGB Sequence

一道有点难想的 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\n", ans);
}
int main() {
  int _ = 1;
  // scanf("%d", &_);
  while(_--) work();
  return 0;
}
posted @ 2020-09-12 22:40  Nylch  阅读(75)  评论(0编辑  收藏  举报