https://ac.nowcoder.com/acm/contest/342/E
题意:给一个匹配的括号串,首先选择一个区间(可以不选),让字符反转,然后隐藏其中一些位置,变成?,让你还原,问可以还原多少种情况。
思路:dp[i][j][k],i表示处理的位置,j表示(比)多几个,k表示当前位置的状态,1表示没有进行反转,2表示正在进行反转,3表示已经完成反转。转移的时候对不同字符根据不同状态进行反转。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mod 1000000007
ll dp[3005][3005][4];
int main()
{
char s[3005];
while(~scanf("%s",s))
{
int len=strlen(s);
memset(dp,0,sizeof(dp));
dp[0][0][1]=1;
for(int i=1; i<=len; i++)
{
if(s[i-1]=='?')
{
for(int k=1; k<=i; k++) //(
{
dp[i][k][1]+=dp[i-1][k-1][1];
dp[i][k][1]%=mod;
dp[i][k][3]+=dp[i-1][k-1][3];
dp[i][k][3]%=mod;
dp[i][k][3]+=dp[i-1][k-1][2];//wu
dp[i][k][3]%=mod;
dp[i][k][2]+=dp[i-1][k-1][1];
dp[i][k][2]%=mod;
dp[i][k][2]+=dp[i-1][k-1][2];
dp[i][k][2]%=mod;
}
for(int k=0; k<=i; k++) //)
{
dp[i][k][1]+=dp[i-1][k+1][1];
dp[i][k][1]%=mod;
dp[i][k][3]+=dp[i-1][k+1][2];
dp[i][k][3]%=mod;
dp[i][k][3]+=dp[i-1][k+1][3];//wu
dp[i][k][3]%=mod;
dp[i][k][2]+=dp[i-1][k+1][1];
dp[i][k][2]%=mod;
dp[i][k][2]+=dp[i-1][k+1][2];
dp[i][k][2]%=mod;
}
}
else if(s[i-1]=='(')
{
for(int k=1; k<=i; k++) //(
{
dp[i][k][1]+=dp[i-1][k-1][1];
dp[i][k][1]%=mod;
dp[i][k][3]+=dp[i-1][k-1][2];
dp[i][k][3]%=mod;
dp[i][k][3]+=dp[i-1][k-1][3];
dp[i][k][3]%=mod;
}
for(int k=0; k<=i; k++)//)
{
dp[i][k][2]+=dp[i-1][k+1][1];
dp[i][k][2]%=mod;
dp[i][k][2]+=dp[i-1][k+1][2];
dp[i][k][2]%=mod;
}
}
else//)
{
for(int k=1; k<=i; k++) //(
{
dp[i][k][2]+=dp[i-1][k-1][1];
dp[i][k][2]%=mod;
dp[i][k][2]+=dp[i-1][k-1][2];
dp[i][k][2]%=mod;
}
for(int k=0; k<=i; k++)//)
{
dp[i][k][1]+=dp[i-1][k+1][1];
dp[i][k][1]%=mod;
dp[i][k][3]+=dp[i-1][k+1][2];
dp[i][k][3]%=mod;
dp[i][k][3]+=dp[i-1][k+1][3];
dp[i][k][3]%=mod;
}
}
}
ll ans=0;
for(int i=1; i<=3; i++)
{
ans+=dp[len][0][i];
ans%=mod;
}
printf("%lld\n",ans);
}
return 0;
}
写的有点麻烦,?时即可以当作(又可以当作),所以可以把问号融合到下两种情况中。