本题一个很巧妙的设计就是dp状态,设计为f[l][r][i][j],从l-r,左右端点是哪个
这样就可以通过递归来计算小区间的值
记住,要先进行字符串的匹配,也就是常规的括号进出栈问题,记录下来每个左括号匹配的右括号的位置
网上有些记录了右括号的匹配左括号是谁,其实没有必要,因为用不大,大概是因为第一个多写了这步,后面的人就懒得改了
#include<algorithm> #include<iostream> #include<cstdio> #include<vector> #include<cstring> #include<set> #include<map> using namespace std; typedef long long ll; const int N=1100; const int mod=1e9+7; ll f[N][N][3][3]; int st[N]; int tmp[N]; void dfs(int l,int r){ if(l+1==r){ f[l][r][0][1]=1; f[l][r][1][0]=1; f[l][r][0][2]=1; f[l][r][2][0]=1; return ; } else if(st[l]==r){ dfs(l+1,r-1); int i,j; for(i=0;i<3;i++){ for(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(i!=1) f[l][r][1][0]=(f[l][r][1][0]+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!=2) f[l][r][2][0]=(f[l][r][2][0]+f[l+1][r-1][i][j])%mod; } } return ; } else{ int p=st[l]; dfs(l,p); dfs(p+1,r); int i,j,k,q; for(i=0;i<3;i++){ for(j=0;j<3;j++){ for(k=0;k<3;k++){ for(q=0;q<3;q++){ if(k!=q||(!k&&!q)){ f[l][r][i][j]=(f[l][r][i][j]+f[l][p][i][k]*f[p+1][r][q][j]%mod)%mod; } } } f[l][r][i][j]%=mod; } } } } int main(){ int i; string s; cin>>s; int cnt=0; memset(f,0,sizeof f); for(i=0;i<s.size();i++){ if(s[i]=='(') tmp[cnt++]=i; else{ st[tmp[cnt-1]]=i; cnt--; } } int len=s.size()-1; dfs(0,len); ll ans=0; int j; for(i=0;i<3;i++){ for(j=0;j<3;j++){ ans=(ans+f[0][len][i][j])%mod; } } cout<<ans<<endl; return 0; }