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;
}
posted @ 2024-02-21 22:23  maple276  阅读(14)  评论(0编辑  收藏  举报