题意:给括号对染色,这里的括号对的确定必须是括号a,b之间必须是没有括号,或者是还有完整的括号
做法:区间DP,先使最小的括号染色,然后根据区间两端是否可以匹配,进行分别计算。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
#define LL long long
#define mod 1000000007
const int LMT=705;
using namespace std;
char str[LMT];
LL dp[LMT][LMT][3][3];//定义的时候要小心啊...
bool is[LMT][LMT];
int main()
{
int len;
LL ans=0;
stack<int>q;
scanf("%s",str);
len=strlen(str);
for(int i=0;i<len;i++)
if(str[i]=='(')q.push(i);
else
{
is[q.top()][i]=1;
q.pop();
}
for(int i=0;i<len-1;i++)
if(is[i][i+1])
{ dp[i][i+1][0][1]=dp[i][i+1][0][2]
=dp[i][i+1][1][0]=dp[i][i+1][2][0]=1;
}
for(int k=3;k<=len;k++)
for(int i=0,j;i+k-1<len;i++)
{
j=i+k-1;
if(is[i][j])//能盖就盖吧
{
for(int c10=0;c10<3;c10++)
for(int c01=0;c01<3;c01++)
if((c10||c01)&&c10*c01==0)
for(int c20=0;c20<3;c20++)
if(c20!=c10||c20*c10==0)
for(int c02=0;c02<3;c02++)
if(c01!=c02||c01*c02==0)
{
dp[i][j][c10][c01]+=dp[i+1][j-1][c20][c02];
dp[i][j][c10][c01]%=mod;
}
}
else if(str[i]=='('&&str[j]==')')
{
int kk;
for(kk=i;kk<=j&&!is[i][kk];kk++);
if(kk<=j)
for(int c10=0;c10<3;c10++)
for(int c01=0;c01<3;c01++)
for(int c20=0;c20<3;c20++)
if(c20!=c01||c20*c01==0)
for(int c02=0;c02<3;c02++)
{
dp[i][j][c10][c02]+=dp[i][kk][c10][c01]*dp[kk+1][j][c20][c02];
dp[i][j][c10][c02]%=mod;
}
}
}
for(int c10=0;c10<3;c10++)
for(int c01=0;c01<3;c01++)
{
ans+=dp[0][len-1][c10][c01];
ans%=mod;
}
printf("%I64d\n",ans);
return 0;
}