zoukankan      html  css  js  c++  java
  • 牛客普及组-合法括号序列

    题目大意

    键盘上有左括号(,右括号),和退格键-,共三个键。

    牛牛希望按键n次,使得输入的字符串恰好一个合法的括号序列。

    每按一次左括号(,字符串末尾追加一个左括号(

    每按一次右括号),字符串末尾追加一个右括号)

    每按一次退格键-,会删掉字符串的最后一个字符,

    特别的,如果字符串为空,牛牛也可以按退格,但是什么都不会发生。

    合法括号序列的定义和上一场比赛中的C题是一样的
    https://www.nowcoder.com/acm/contest/164/C

    输出方案数对p取模,注意p可能不是质数。

    注:只要按键方法不同,就是不同的方案,即使得到的序列一样。


     此题有一个比较麻烦的地方就是需要把删除的贡献也考虑在内

    不妨将当前括号序列长度考虑在内

    设 g[i][j] 表示进行了 i 次操作后序列长度为 j 的方案数

    转移也很好想 : g[i][j] = g[i -1][j - 1] + g[i - 1][j + 1] * 2

    乘以 2 就是填入左 / 右括号,j = 0 时把 j - 1 改成 0

    由于统计答案时统计的是合法括号序,就再 dp 出长度为 i 时的合法括号序即可

    状态设计为 f[i][j] 表示当前长度为 i ,还有 j 个左括号未匹配


    代码:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<cstdio>
    using namespace std;
    
    typedef long long ll;
    const int MAXN = 1005;
    
    int n;
    ll f[MAXN][MAXN], g[MAXN][MAXN];
    ll p, ans;
    
    int main() {
    	scanf("%d%lld", &n, &p);
    	f[0][0] = 1ll;
    	for(int i = 1; i <= n; ++i) {
    		f[i][0] = f[i - 1][1];
    		for(int j = 1; j <= i; ++j) {
    			f[i][j] = (f[i][j] + f[i - 1][j + 1] + f[i - 1][j - 1]) % p;
    		}
    	}
    	g[0][0] = 1ll;
    	for(int i = 1; i <= n; ++i) {
    		for(int j = 0; j <= i; ++j) {
    			g[i][j] = (g[i - 1][max(j - 1, 0)] + g[i - 1][j + 1] * 2) % p;
    		}
    	}
    	ans = g[n][0];
    	for(int j = 2; j <= n; j += 2) {
    		ans = (ans + f[j][0] * g[n][j]) % p;
    	}
    	printf("%lld
    ", ans);
    	return 0;
    }
    

     因为合法的括号序长度一定是偶数,所以枚举长度也枚举偶数

    禁止诸如开发者知识库/布布扣/码迷/学步园/马开东等 copy 他人博文乃至博客的网站转载 ,用户转载请注明出处:https://www.cnblogs.com/xcysblog/
  • 相关阅读:
    [转]回车和换行
    计算机常见缩略词备忘录
    Linux多线程编程阅读链接
    字符串匹配KMP算法
    k8s测试集群部署
    搭建Vmware Harbor 镜像仓库
    GitLab搭建
    Gerrit2安装配置
    linux文件系统问题:wrong fs type, bad option, bad superblock
    Docker容器内不能联网的6种解决方案
  • 原文地址:https://www.cnblogs.com/xcysblog/p/9661835.html
Copyright © 2011-2022 走看看