题解 [CSP-S 2021] 括号序列

传送门

考场上由于策略原因打了个暴力就跑路了
DP只是简单想了想

  • 貌似括号序列相关的方案数类的题常与区间DP有关?

考虑令 \(f_{l, r}\) 为区间 \([l, r]\) 为合法括号序列的方案数
\(u_{l, r}\) 为形如 \(AS\) 方案数
\(v_{l, r}\) 为形如 \(SA\) 方案数
\(t_{l, r}\) 为区间 \([l, r]\) 是合法 \(S\) 的方案数
转移按题意划分为两部分
但注意到会在 \(()()()\) 的情况算重
于是再定义一个 \(g_{l, r}\) 为区间 \([l, r]\) 为不能从中间划分为两个被括起来的括号序列的方案数即可

Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 510
#define ll long long
//#define int long long

int n, k;
char s[N];
const ll mod=1e9+7;

namespace force{
	int pos[N], tot, ans;
	char sta[N], sta2[N];
	const char tab[]={'(', ')', '*'};
	bool check() {
		// cout<<"check: "; for (int i=1; i<=n; ++i) cout<<s[i]<<' '; cout<<endl;
		int sum=0;
		for (int i=1; i<=n; ++i)
			if (s[i]=='(') ++sum;
			else if (s[i]==')') --sum;
		if (sum!=0) return 0;
		int top=0;
		for (int i=1,lst=0; i<=n; ++i) {
			if (s[i]=='*') {
				++lst;
				if (lst>k) return 0;
			}
			else lst=0;
		}
		int lst=0;
		for (int i=1; i<=n; ++i) {
			if (s[i]=='*') lst=1;
			else if (s[i]=='(') {
				if (lst) sta[++top]='S', lst=0;
				sta[++top]='(';
			}
			else {
				if (lst) sta[++top]='S', lst=0;
				sta[++top]=')';
			}
		}
		if (lst) sta[++top]='S';
		// cout<<"sta: "; for (int i=1; i<=top; ++i) cout<<sta[i]<<' '; cout<<endl;
		int top2=0;
		for (int i=1; i<=top; ++i) {
			if (sta[i]=='(') sta2[++top2]='(';
			else if (sta[i]==')') {
				if (top2>0 && sta2[top2]=='(') sta2[top2]='A';
				else if (top2>1 && sta2[top2-1]=='(' && sta2[top2]=='A') sta2[--top2]='A';
				else if (top2>1 && sta2[top2-1]=='(' && sta2[top2]=='S') sta2[--top2]='A';
				else if (top2>2 && sta2[top2-2]=='(' && sta2[top2-1]=='S' && sta2[top2]=='A') top2-=2, sta2[top2]='A';
				else if (top2>2 && sta2[top2-2]=='(' && sta2[top2-1]=='A' && sta2[top2]=='S') top2-=2, sta2[top2]='A';
				else sta2[++top2]=')';
			}
			else sta2[++top2]='S';
			while (1) {
				if (top2>1 && sta2[top2]=='A' && sta2[top2-1]=='A') sta2[--top2]='A';
				else if (top2>2 && sta2[top2-2]=='A' && sta2[top2-1]=='S' && sta2[top2]=='A') top2-=2, sta2[top2]='A';
				else break;
			}
		}
		// cout<<"sta2: "; for (int i=1; i<=top2; ++i) cout<<sta2[i]<<' '; cout<<endl;
		return bool(top2==1 && sta2[1]=='A');
	}
	void dfs(int u) {
		if (u>tot) {if (check()) ++ans; return ;}
		for (int i=1; i<=3; ++i) {
			s[pos[u]]=tab[i-1];
			dfs(u+1);
		}
	}
	void solve() {
		for (int i=1; i<=n; ++i) if (s[i]=='?') pos[++tot]=i;
		dfs(1);
		printf("%d\n", ans);
		exit(0);
	}
}

namespace task{
	ll f[N][N], g[N][N], u[N][N], v[N][N], t[N][N];
	void solve() {
		for (int i=1; i<=n; ++i) t[i][i]=(s[i]=='*' || s[i]=='?');
		for (int len=2; len<=n; ++len) {
			for (int i=1,j; (j=i+len-1)<=n; ++i) {
				for (int q=i; q<j; ++q) {
					t[i][j]=(len<=k&&t[i][q]&&t[q+1][j]);
					u[i][j]=(u[i][j]+t[i][q]*f[q+1][j])%mod;
					v[i][j]=(v[i][j]+f[i][q]*t[q+1][j])%mod;
					f[i][j]=(f[i][j]+g[i][q]*(u[q+1][j]+f[q+1][j]))%mod;
				}
				f[i][j]=(f[i][j]+((s[i]=='('||s[i]=='?')&&(s[j]==')'||s[j]=='?'))*(f[i+1][j-1]+t[i+1][j-1]+u[i+1][j-1]+v[i+1][j-1]+(len==2)))%mod;
				g[i][j]=(g[i][j]+((s[i]=='('||s[i]=='?')&&(s[j]==')'||s[j]=='?'))*(f[i+1][j-1]+t[i+1][j-1]+u[i+1][j-1]+v[i+1][j-1]+(len==2)))%mod;
				// printf("f[%d][%d]=%lld\n", i, j, f[i][j]);
			}
		}
		printf("%lld\n", f[1][n]);
		exit(0);
	}
}

signed main()
{
	//freopen("bracket.in", "r", stdin);
	//freopen("bracket.out", "w", stdout);

	scanf("%d%d", &n, &k);
	scanf("%s", s+1);
	// force::solve();
	task::solve();

	return 0;
}
posted @ 2021-10-25 15:22  Administrator-09  阅读(0)  评论(0编辑  收藏  举报