题目
思路
结论: 对于一个串
S
S
S 如果有:
对任意前缀
p
p
p:
)
)
) 个数
≤
\le
≤ 2
(
(
( 个数
对任意后缀
q
q
q:
(
(
( 个数
≤
\le
≤ 2
)
)
) 个数
那么这个串就是合法的
本质上是考虑模拟弹栈的过程
如果有
(
(
∣
)
)
)
)
((|))))
((∣))))
显然右括号太多可以变成两种颜色
为什么此时不考虑左括号太多?
因为此时是后缀判断了
然后
f
i
,
j
,
k
f_{i,j,k}
fi,j,k 前
i
i
i 个放了
j
j
j 个左括号最小为
k
k
k 的方案数
时间复杂度:
O
(
n
3
)
O(n^3)
O(n3)
代码
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<stack>
#include<cctype>
#include<vector>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<climits>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
#define ULL unsigned long long
int read(){
bool f=0;int x=0;char c=getchar();
while(!isdigit(c)) f=(c=='-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
return !f?x:-x;
}
void print(int x){
if(x<10){
if(x<0) putchar('-'),x=-x;
else{
putchar('0'+x);
return ;
}
}
print(x/10);
putchar('0'+x%10);
return ;
}
#define fi first
#define se second
#define mp make_pair
const int MAXN=300;
const int INF=0x3f3f3f3f;
const int Mod=(int)(1e9+7);
int Add(int x,int y){x+=y;return x>=Mod?x-Mod:x;}
int f[2][MAXN+5][3*MAXN+5],ans[MAXN+5];
int main(){
//freopen("parentrises.in","r",stdin);
//freopen("parentrises.out","w",stdout);
f[0][0][301]=1;
for(int i=0,nw=0,nxt=1;i<=300;i++,nw^=1,nxt^=1){
for(int j=0;j<=i+1;j++)
for(int k=301-(i+1);k<=301+2*(i+1);k++)
f[nxt][j][k]=0;
for(int j=0;j<=i;j++)
for(int k=301-i;k<=301+2*i;k++){
if(f[nw][j][k]){//放左括号
f[nxt][j+1][min(300,k-1)]=Add(f[nxt][j+1][min(300,k-1)],f[nw][j][k]);
if(i+1-j<=2*j)//放右括号
f[nxt][j][k+2]=Add(f[nxt][j][k+2],f[nw][j][k]);
}
if(k>=301) ans[i]=Add(ans[i],f[nw][j][k]);
}
}
int T=read();
while(T--)
printf("%d\n",ans[read()]);
return 0;
}