CodeForces 149D Coloring Brackets

区间DP。dp[i][j][h][k]表示[i,j]这段区间染色,左端点为颜色h,右端点为颜色k的方案数。

递推式很容易写出来。注意中间过程爆int。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;

const int MOD = 1e9 + 7;
const int maxn = 1000;
char s[maxn];
long long dp[maxn][maxn][3][3];
int len;
int link[maxn];
int Stack[maxn], top;

void init()
{
    len = strlen(s);
    for (int i = len - 1; i >= 0; i--) s[i + 1] = s[i];
    memset(dp, 0, sizeof dp);
}

void work()
{
    for (int i = 1; i <= len; i++)
    {
        if (i % 2 != 0) continue;
        for (int j = 1; j <= len; j++)
        {
            int st = j, en = st + i - 1;
            if (en > len) break;
            if (i == 2)
            {
                if (s[st] == ‘(‘&&s[en] == ‘)‘)
                {
                    dp[st][en][1][0] = dp[st][en][2][0] = 1;
                    dp[st][en][0][1] = dp[st][en][0][2] = 1;
                }
                continue;
            }

            if (link[st]==en)
            {
                for (int k = 0; k<3; k++)
                    for (int h = 0; h<3; h++)
                        if (k != 1) dp[st][en][1][0] = (dp[st][en][1][0] + dp[st + 1][en - 1][k][h]) % MOD;

                for (int k = 0; k<3; k++)
                    for (int h = 0; h<3; h++)
                        if (k != 2) dp[st][en][2][0] = (dp[st][en][2][0] + dp[st + 1][en - 1][k][h]) % MOD;

                for (int k = 0; k<3; k++)
                    for (int h = 0; h<3; h++)
                        if (h != 1) dp[st][en][0][1] = (dp[st][en][0][1] + dp[st + 1][en - 1][k][h]) % MOD;

                for (int k = 0; k<3; k++)
                    for (int h = 0; h<3; h++)
                        if (h != 2) dp[st][en][0][2] = (dp[st][en][0][2] + dp[st + 1][en - 1][k][h]) % MOD;
                continue;
            }

            int p = link[st];
            for (int k = 0; k<3; k++)
                for (int h = 0; h<3; h++)
                    for (int kk = 0; kk<3; kk++)
                        for (int hh = 0; hh<3; hh++)
                            if (!((kk == 1 && hh == 1) || (kk == 2 && hh == 2)))
                                dp[st][en][k][h] = (
                                dp[st][en][k][h] +
                                (dp[st][p][k][kk] * dp[p + 1][en][hh][h]) % MOD
                                ) % MOD;
        }
    }
    long long ans = 0;
    for (int k = 0; k<3; k++)
        for (int h = 0; h<3; h++)
            ans = (ans + dp[1][len][k][h]) % MOD;
    printf("%lld\n", ans);
}

void f()
{
    memset(link, -1, sizeof link);
    top = -1;
    for (int i = 1; i <= len; i++)
    {
        if (top == -1) Stack[++top] = i;
        else
        {
            if (s[i] == ‘)‘) { link[Stack[top]] = i; top--; }
            else Stack[++top] = i;
        }
    }
}

int main()
{
    while (~scanf("%s", s))
    {
        init();
        f();
        work();
    }
    return 0;
}
时间: 2024-08-05 04:03:08

CodeForces 149D Coloring Brackets的相关文章

codeforces 149D - Coloring Brackets (区间dp)

题目大意: 给出一组合法的括号. 括号要么不涂颜色,要么就涂上红色或者绿色. 匹配的括号只能有一个有颜色. 两个相邻的括号不能有相同的颜色. 思路分析: 因为是一个合法的括号序列. 所以每个括号与之匹配的位置是一定的. 那么就可以将这个序列分成两个区间. (L - match[L] )  (match[L]+1, R) 用递归先处理小区间,再转移大区间. 因为条件的限制,所以记录区间的同时,还要记录区间端点的颜色. 然后就是一个递归的过程. #include <cstdio> #include

CodeForces 149D Coloring Brackets (区间D)

题意: 给一个合法的括号序列,仅含()这两种.现在要为每对括号中的其中一个括号上色,有两种可选:蓝or红.要求不能有两个同颜色的括号相邻,问有多少种染色的方法? 思路: 这题的模拟成分比较多吧?两种颜色还有无色,用2个bit就可以表示了.然后就是各种转移,注意结果可能非常大,要取模后输出.转移主要是不让同颜色的括号在一起.处理时可以用DFS,在区间[L,R]中找到距离最远的所有合法括号,递归往下处理子问题,直到剩下一对括号直接处理就行了. 1 //#include <bits/stdc++.h>

codeferces 149D Coloring Brackets 区间dp

http://codeforces.com/problemset/problem/149/D 题目大致意思是给你一串字符串,只有小括号,并且已经符合括号匹配规则,现在要给这些括号涂色,给出一些涂色规则,求涂色的方案数. 1: 括号要么不被涂色,要么被涂成蓝色,要么被涂成红色. 2:两个相互匹配的括号有且仅有一个被涂色. 3:相邻两个括号不可以有相同颜色. 这里当然也是想到对区 [l, r] 间进行dp,但是这里对颜色有依赖关系,所以还需要记入 l 和 r 颜色的状态,一开始打算只用一维记录两个点

CF# 149 D Coloring Brackets(区间dp)

D - Coloring Brackets Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit Status Practice CodeForces 149D Description Once Petya read a problem about a bracket sequence. He gave it much thought but didn't find a solut

CF149D. Coloring Brackets[区间DP !]

不知道为什么居中了,先把代码放这 #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int N=705,MOD=1e9+7; char s[N]; long long n,f[N][N][5][5]; int st[N],top=0,m[N]; void match(){ for(int i=1;i<=

CodeForces 149D 区间DP Coloring Brackets

染色有三个条件: 对于每个点来说要么不染色,要么染红色,要么染蓝色 对于每对配对的括号来说,有且只有一个一边的括号被染色 相邻的括号不能染成相同的颜色 首先可以根据给出的括号序列计算出括号的配对情况,具体来说就是第i个括号与R[i]个括号配对. 对于一个正规配对括号序列(correct bracket sequence),d(l, r, c1, c2)表示括号序列S[i]~S[j],i左边括号的颜色是c1,r右边的括号颜色是c2(0表示没有染色),这样的序列的染色方法数. 与S[i]配对的可能是

Codeforces Round #106 (Div. 2) Coloring Brackets(区间DP)

题意:给你一组括号序列,让你进行染色,对于每个括号,有无色,红色,蓝色三种方案.染色需要满足这样的条件:互相匹配的括号,有且只有一个有颜色,相邻的括号不能颜色相同(可以同为无色),问合法的染色方案数(答案%1e9+7) 分析:根据题意能够看出是区间DP,并且状态转移的时候,依赖于左右两端的颜色,所以我们用dp[i][j][x][y]表示i到j的区间内左端颜色为x,右端颜色为y的方案数. 区间[i,j]可以由两种情况得到,一种是str[i],str[j]匹配,产生新的相匹配的括号,考虑在只有一端染

Codeforces 1197F Coloring Game 矩阵快速幂 (看题解)

Coloring Game 我写的复杂度是 1000 * 64 * 64 * 64 * log(1e9),  感觉这个东西是很好想的, 肯定是T了的. 其实可以优化掉一个64, 就是在转移的时候用64 * 64的矩阵和 64 * 1的答案相邻相乘, 这样就可以优化掉一个64了, 以前好像没有见过这种小技巧. #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize(4) #include<bits/stdc++.h>

CodeForces 711C Coloring Trees (DP)

题意:给定n棵树,其中有一些已经涂了颜色,然后让你把没有涂色的树涂色使得所有的树能够恰好分成k组,让你求最少的花费是多少. 析:这是一个DP题,dp[i][j][k]表示第 i 棵树涂第 j 种颜色恰好分成 k 组,然后状态转移方程是什么呢? 如果第 i 棵已经涂了,那么要么和第 i-1 棵一组,要么不和第 i-1 棵一组. 如果第 i 棵没有涂,和上面差不多,就是加上要涂的费用,并且要选择最少的. 代码如下: #pragma comment(linker, "/STACK:1024000000