• 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; 
     } 
    
    
  • 相关阅读:
    loj 1257 (求树上每一个点到树上另一个点的最长距离)
    loj 1032 数位dp
    loj 1030概率dp
    loj1011 状态压缩
    java大数取模
    求阶乘的位数
    loj 1426(dfs + bfs)
    携程greenlet模块使用
    如何让socket编程非阻塞?
    分别用request和socket给百多发送请求
  • 原文地址:https://www.cnblogs.com/yjyl0098/p/15468150.html
Copyright © 2020-2023  润新知