CSP-S2021 T2 括号序列 题解

\(这道题考场上没拿下真的很不应该。看数据范围\) n <= 500 \(就知道是一道裸的区间dp题\)
\(转移方程甚至直接按照题目要求来模拟就可以了\)

\(首先先加上一三两种情况的答案 然后是子区间的一三两种情况的方案数乘上第二种情况的方案数\)
\(对于第二种情况要多考虑一下 我们只计算*号或者?号都在左侧的就没问题了 保证不重复\)

\(剩下没什么大问题。细节说多也不多,想想也就知道了。\)

code:


#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>

using namespace std;

const int N = 510;
const int mod = 1e9 + 7;

char s[N];

inline int read()
{
	char ch = getchar();int f = 0,x = 0;
	while(ch > '9' || ch < '0') f |= (ch == '-'),ch = getchar();
	while(ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch - '0'),ch = getchar();
	if(f) x = -x;
	return x;
}

inline void add(int &x,int y)
{
	x += y;
	if(x >= mod) x -= mod;
}

int n,K;
int dp[N][N],dp2[N][N],dp3[N][N];
int c[N];
bool check(int l,int r)
{
	return c[r] == c[l - 1];
}

int main()
{
	 n = read(),K = read();
	 scanf("%s",s + 1);
	 for(register int i = 1; i <= n; ++ i)
		c[i] = c[i-1] + (s[i] == '(' || s[i] == ')'); 
	 for(register int len = 2; len <= n; ++ len)
	   for(register int i = 1; i + len - 1 <= n; ++ i)
	   {
	   	    int j = i + len - 1;
	   	    if(s[i] == '*' || s[j] == '*' || s[i] == ')' || s[j] == '(')
				;  //直接无视不合法的情况 
	   	    else
	   	    {
	   	    	if(len <= K + 2 && check(i + 1,j - 1)) 
				   dp[i][j] = 1;
				//1;
			    add(dp[i][j],dp[i + 1][j - 1]);
			    for(register int k = 1; k <= K && k <= len - 4; ++ k)
			    {
			    	if(check(i + 1,i + k))
			    	   add(dp[i][j],dp[i + k + 1][j - 1]);
			    	else break;
				}
				
		        for(register int k = 1; k <= K && k <= len - 4; ++ k)
		        {
		        	if(check(j - k,j - 1)) 
		        	   add(dp[i][j],dp[i + 1][j - k - 1]);
		            else break;
				}
				//3
				//cout << dp[i][j] << endl;
				dp3[i][j] = dp[i][j];
				for(register int k = i + 1; k < j; ++ k)
				  add(dp[i][j],1LL * dp3[i][k - 1] * dp2[k][j] % mod);
			}
	   	    	//2
	   	    	//cout << dp[i][j] << endl;
	   	        for(register int k = 0; k <= K && k <= len - 2; ++ k)
	   	           if(check(i,i + k - 1))
	   	              add(dp2[i][j],dp[i + k][j]);
	   	           else 
					  break; // **()()... 
			   
		}
		printf("%d", dp[1][n]);
		return 0; 
 } 

posted @ 2021-10-26 22:11  Linyk  阅读(49)  评论(0编辑  收藏  举报