DP - 區間DP - Coloring Brackets - CodeForces - 149D

DP - 區間DP - Coloring Brackets - CodeForces - 149D

題意:

"()"s()滿給定一個僅由"()"構成的括號序列s(保證整個序列能成功匹配),現給括號上色,需滿足:\\①、每個括號要麼不上色,要麼紅色,要麼藍色。\\②、一對匹配的括號僅有一個能夠被上色。\\③、相鄰的括號顏色不能相同,但可以都不上色。

109+7要求整個序列上色的方案總數,答案對10^9+7取模。

Examples

Input:
(())

Output:
12


Input:
(()())

Output:
40


Input:
()

Output:
4

數據範圍:

2<=s<=700Time limit2000msMemory limit262144kB2<=|s|<=700\\Time \ limit:2000 ms,Memory \ limit:262144 kB

分析:


與經典的括號序列匹配問題類似——《Brackets - POJ - 2955》,一個序列的染色方案數量的計算是相互獨立的。

f[l][r][a][b][l,r]larbab=012012狀態表示:f[l][r][a][b]表示區間[l,r]內,l被染上顏色a,r被染上顏色b的方案總數,a、b=0,1,2。\\0:不上色,1:紅色,2:藍色。

狀態計算:整個區間的方案總數,具體分爲兩種情況:

s[l]s[r]①、當s[l]與s[r]能夠匹配,具體又可分爲四種情況:

a=1s[l+1]s[r]f[l][r][1][0]+=f[l+1][r1][i][j]i1\qquadⅠ、a=1時,s[l+1]不能染相同的紅色,s[r]不能染色,故f[l][r][1][0]+=f[l+1][r-1][i][j],i≠1。

a=2s[l+1]s[r]f[l][r][2][0]+=f[l+1][r1][i][j]i2\qquadⅡ、a=2時,s[l+1]不能染相同的藍色,s[r]不能染色,故f[l][r][2][0]+=f[l+1][r-1][i][j],i≠2。

b=1s[r1]s[l]f[l][r][0][1]+=f[l+1][r1][i][j]j1\qquadⅢ、b=1時,s[r-1]不能染相同的紅色,s[l]不能染色,故f[l][r][0][1]+=f[l+1][r-1][i][j],j≠1。

b=2s[r1]s[l]f[l][r][0][2]+=f[l+1][r1][i][j]j2\qquadⅣ、b=2時,s[r-1]不能染相同的藍色,s[l]不能染色,故f[l][r][0][2]+=f[l+1][r-1][i][j],j≠2。

s[l]s[r][l,r]f[l,r][l,k][k+1,r]f[l][r][a][b]+=f[l][k][a][i]×f[k+1][r][j][b]kla,b=0,1,2iji=j=0②、s[l]與s[r]不匹配,由乘法原理,\\\qquad 區間[l,r]的方案總數f[l,r]可以分爲[l,k]的方案總數與區間[k+1,r]的方案總數之積。\\\qquad f[l][r][a][b]+=f[l][k][a][i]×f[k+1][r][j][b],k是與l匹配的括號下標。a ,b=0,1,2且i≠j或者i=j=0。

具體落實:

21①、初始化邊界:當區間長度爲2時,合法方案數都爲1。
f[l][r][0][1]=1f[l][r][0][2]=1;f[l][r][1][0]=1;f[l][r][2][0]=1;\qquad 即:f[l][r][0][1] = 1\\ \qquad \qquad f[l][r][0][2] = 1;\\ \qquad \qquad f[l][r][1][0] = 1;\\ \qquad \qquad f[l][r][2][0] = 1;

s[l]s[r]lr②、爲了簡化代碼,先將括號的匹配條件映射到下標上來。若s[l]與s[r]匹配,將下標l映射到r。

③、每個區間我們僅需計算一次,可以數組標記一下被搜索過的區間。

f1091018ll④、數組f的值可能達到10^9,乘積會達到10^{18},因此用ll類型來存儲。

代碼:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<stack>

#define ll long long

using namespace std;

const int N=710,mod=1e9+7;

int mp[N],n;
ll f[N][N][3][3];
char s[N];
bool vis[N][N];

void trans()
{
    stack<int> S;
    for(int i=0;i<n;i++)
        if(s[i]=='(')
            S.push(i);
        else
        {
            int tmp=S.top();
            S.pop();
            mp[tmp]=i;
            mp[i]=tmp;
        }
}

void dfs(int l,int r)
{
    if(vis[l][r]) return ;
    vis[l][r]=true;
    
    if(l+1==r) 
    {
        f[l][r][0][1]=f[l][r][1][0]=f[l][r][0][2]=f[l][r][2][0]=1;
        return ;  //  遞歸出口
    }

    if(mp[l]==r)
    {
        dfs(l+1,r-1); //先計算長度短的情況

        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
            {
                if(j!=1) f[l][r][0][1]=(f[l][r][0][1]+f[l+1][r-1][i][j])%mod;
                if(j!=2) f[l][r][0][2]=(f[l][r][0][2]+f[l+1][r-1][i][j])%mod;
                if(i!=1) f[l][r][1][0]=(f[l][r][1][0]+f[l+1][r-1][i][j])%mod;
                if(i!=2) f[l][r][2][0]=(f[l][r][2][0]+f[l+1][r-1][i][j])%mod;
            }

    }
    
    else 
    {
        int k=mp[l];
        dfs(l,k);
        dfs(k+1,r);
        for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
        for(int a=0;a<3;a++)
        for(int b=0;b<3;b++)
            if( (a==0&&b==0) || a!=b)
                f[l][r][i][j]=(f[l][r][i][j]+f[l][k][i][a]*f[k+1][r][b][j]%mod)%mod;
    }
}

int main()
{
    scanf("%s",s);
    n=strlen(s);
    trans();

    dfs(0,n-1);
    int res=0;
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
            res=(res+f[0][n-1][i][j])%mod;

    cout<<res<<endl;
    
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章