bzoj 2461: [BeiJing2011]符环

f[i][s1][s2][s3]枚举到前i个字符,前半段左括号-右括号的值是i,后半段未匹配的左括号个数是s2,未匹配的右括号个数是s3.
后半段去掉已匹配的括号后一定是这样:)))(((。
转移时依次枚举左边添加左括号,左边添加右括号。注意在右面添加右括号时,一种情况是减少一个未匹配的左括号,一种情况是增加一个未匹配的右括号。
然后记忆化搜索。
    
    
    
    
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
 
#define ll long long
#define inf 1e9
#define eps 1e-8
#define md
using namespace std;
ll f[55][55][55][55];
char st[55];
ll dp(int i,int s1,int s2,int s3)
{
if (s1<0||s2<0||s3<0) return 0;
if (f[i][s1][s2][s3]!=-1) return f[i][s1][s2][s3];
if (i<1) return f[i][s1][s2][s3]=0;
ll &x=f[i][s1][s2][s3]; x=0;
if (st[i]=='S')
{
x+=dp(i-1,s1-1,s2-1,s3)+dp(i-1,s1+1,s2+1,s3);
if (s2==0) x+=dp(i-1,s1+1,s2,s3-1);
}
else
{
if (s2==0) x+=dp(i-1,s1-1,s2,s3-1);
x+=dp(i-1,s1+1,s2-1,s3)+dp(i-1,s1-1,s2+1,s3);
}
return x;
}
 
int main()
{
int tt;
scanf("%d",&tt);
while (tt--)
{
memset(f,-1,sizeof(f));
scanf("%s",st);
int n=strlen(st); ll ans=0;
if (st[0]=='S') f[0][1][1][0]=1; else f[0][1][0][1]=1;
for (int i=0;i<=n;i++) ans+=dp(n-1,i,0,i);
printf("%lld\n",ans);
//printf("%lld %lld %lld\n",f[0][1][1][0],f[1][0][0][0],f[2][1][0][1]);
}
return 0;
}

你可能感兴趣的:(bzoj 2461: [BeiJing2011]符环)