csp-s2021 括号序列

  • 前言

到刚才才发现这道题是如此的简单,写起来比T3还要好。

全都我代码能力太弱了,T3一开始选错了实现方法,调调错错错错调调调调错错错错调调调调错错错错调调……(以下省略一万字),硬生生占用了近三个小时,最后还被扣了12分,最重要的是它让我没有时间去思考T2……

当然失败原因不能全怪T3,我一开始想错了,以为是个线性DP(毕竟远古括号序列匹配问题是线性解决),就准备在朴素的问题上加各种附加条件,最后成功地加到了7维,当时我一看,好家伙这还写个*,于是就放弃了。

之后偶然听谁说它是个区间DP,顿时……

怎么说呢,茅塞顿开豁然开朗,以及愈发坚定了自己是个傻逼的观念。

  • 正文

其实就是一个区间DP。按照题目中的描述去写就行了,只是有一点需要注意的,就比如(A)(B)(C)会被(A)+(B)(C)(A)(B)+(C)重复计算。特殊处理一下,即考虑对于一对括号并列的情况只由第一个“单独超级括号”和后面的一坨东西转移即可,这样就不会出现重复计算的情况。

写起来很简单,甚至1000个字符都用不上。

#include<cstdio>
#define zczc
#define ll long long
const int N=510;
const int mod=1e9+7;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar(); }
    wh*=f;return;
}
inline void add(ll &s1,ll s2){
	s1+=s2;s1%=mod;return;
}

int m,n;
bool tl[N],tr[N],ts[N];
char w[N];
ll f[N][N],fs[N][N],g[N][N],fg[N][N];

signed main(){
	
	#ifdef zczc
	freopen("in.txt","r",stdin);
	#endif
	
	read(m);read(n);
	scanf("%s",w+1);
	for(int i=1;i<=m;i++){
		g[i][i-1]=true;
		tl[i]=(w[i]=='('||w[i]=='?');
		tr[i]=(w[i]==')'||w[i]=='?');
		ts[i]=(w[i]=='*'||w[i]=='?');
		for(int j=i;j<=m&&j<=i+n-1;j++){
			g[i][j]=((g[i][j-1]!=0)&&(w[j]=='*'||w[j]=='?'));
		}
		g[i][i-1]=false;
	}
	for(int len=1;len<m;len++){
		for(int l=1;l+len<=m;l++){
			int r=l+len;
			if(len==1){
				fs[l][r]=f[l][r]=(tl[l]&tr[r]);
				continue;
			}
			if(tl[l]&&tr[r]){
				add(fs[l][r],f[l+1][r-1]);
				add(fs[l][r],g[l+1][r-1]);
				for(int i=l+1;i<r;i++){
					add(fs[l][r],g[l+1][i]*f[i+1][r-1]);
					add(fs[l][r],g[i][r-1]*f[l+1][i-1]);
				}
			}
			f[l][r]=fs[l][r];
			for(int i=l;i<r;i++){
				add(fg[l][r],g[l][i]*f[i+1][r]);
				add(f[l][r],fs[l][i]*f[i+1][r]);
				add(f[l][r],fs[l][i]*fg[i+1][r]);
			}
		}
	}
	printf("%lld",f[1][m]);
	
	return 0;
}
posted @ 2021-11-06 18:27  Feyn618  阅读(90)  评论(0编辑  收藏  举报