ARC074 E - RGB Sequence 题解
E:
题意:给长度为n的序列填上RGB三种颜色,要求满足所有条件:\(l_i\) 到 \(r_i\) 之间正好有 \(x_i\) 种颜色。求方案数。n<=300
发现只有三种颜色,区间颜色数只关心每个颜色最后一次出现的位置,所以一开始我想设 \(f[i][a][b]\) 表示考虑了前 i 个位置,R 最后一次在 a,G 最后一次在 b 的方案数。我以为 B 最后一次的位置可以推出来,结果发现是错的推不出来。
另一个我没想到的点是:在考虑前 i 个位置怎么填时,我们不需要关心 r 大于 i 的限制。就算某个情况在前 i 个位置满足,到了右面 r 的位置无法满足了,那也是 \(f[r]\) 处的 dp 值无效,我们可以把它设为0,但是前面的 dp 状态依然认为是有效的。
Solution:
把我前面说的错误状态 \(f[i][a][b]\) 改为 \(f[a][b][c]\) ,表示每一种颜色最后一次的位置,这样的话 \(i=max\{a,b,c\}\) ,已经更新到的位置 i 也是能表示出来的。
转移方程:
\(f[i+1][b][c] += f[a][b][c]\)
\(f[a][i+1][c]+=f[a][b][c]\)
\(f[a][b][i+1]+=f[a][b][c]\)
分别表示下一个位置填哪个颜色。通过先枚举 i ,再枚举剩下两个不是 i 的颜色,每一个dp状态只会访问一次,转移是O(n^3)。
之后是限制,对于状态 \(f[a][b][c]\),我们可以检验每个 \(r=i\) 的限制,查看状态的合法性,不合法设成0就行了。思考可知,每个限制最多检验n2个状态,一共n个限制,所以检验也是O(n3)的。
统计答案也很简单。
这种状态里隐含位置 i 的dp题还是挺有趣的。
const ll p=1000000007;
ll T;
ll n,m;
struct E{ ll l,x; };
vector <E> g[N];
ll f[303][303][303];
ll ans;
inline bool check(ll i,ll j,ll k,ll r) {
for(auto v : g[r]) {
ll res = 0;
if(i>=v.l) res++;
if(j>=v.l) res++;
if(k>=v.l) res++;
if(res!=v.x) return 0;
}
return 1;
}
int main() {
ll x,y,z;
n = read(); m = read();
for(ll i=1;i<=m;i++) {
x = read(); y = read(); z = read();
g[y].push_back({x,z});
}
f[1][0][0] = f[0][1][0] = f[0][0][1] = 1;
for(ll r=1;r<=n;r++) {
for(ll j=0;j<=r;j++)
for(ll k=0;k<=r;k++)
if(check(r,j,k,r)) {
if(r==n) (ans += f[r][j][k]) %= p;
(f[r+1][j][k] += f[r][j][k]) %= p;
(f[r][r+1][k] += f[r][j][k]) %= p;
(f[r][j][r+1] += f[r][j][k]) %= p;
}
for(ll i=0;i<=r;i++)
for(ll k=0;k<=r;k++)
if(check(i,r,k,r)) {
if(r==n) (ans += f[i][r][k]) %= p;
(f[r+1][r][k] += f[i][r][k]) %= p;
(f[i][r+1][k] += f[i][r][k]) %= p;
(f[i][r][r+1] += f[i][r][k]) %= p;
}
for(ll i=0;i<=r;i++)
for(ll j=0;j<=r;j++)
if(check(i,j,r,r)) {
if(r==n) (ans += f[i][j][r]) %= p;
(f[r+1][j][r] += f[i][j][r]) %= p;
(f[i][r+1][r] += f[i][j][r]) %= p;
(f[i][j][r+1] += f[i][j][r]) %= p;
}
}
cout<<ans;
return 0;
}