zoukankan      html  css  js  c++  java
  • [CSP-S模拟测试]:简单的序列(DP)

    题目描述

    从前有个括号序列$s$,满足$|s|=m$。你需要统计括号序列对$(p,q)$的数量。
    其中$(p,q)$满足$|p|+|s|+|q|=n$,且$p+s+q$是一个合法的括号序列。


    输入格式

    从文件$bracket.in$中读入数据。第一行两个正整数$n,m$。
    第二行一个长度为$m$的括号序列,表示$s$。


    输出格式

    输出到文件$bracket.out$中。
    输出一行一个整数,表示符合条件的$(p,q)$的数量对$10^9+7$取模的值。


    样例

    样例输入1:

    4 1 (

    样例输出1:

    4

    样例输入2:

    4 4 (())

    样例输出2:

    1

    样例输入3:

    4 3 (((

    样例输出3:

    0


    数据范围与提示

    对于$10\%$的数据,$nleqslant 20$;
    对于$25\%$的数据,$nleqslant 200$;
    对于另外$5\%$的数据,$n=m$;
    对于$55\%$的数据,$n−mleqslant 200$;
    对于$100\%$的数据,$1leqslant mleqslant nleqslant 10^5,n−mleqslant 2,000$。


    题解

    首先,不妨设左括号为$+1$,右括号为$-1$,那么要满足最后和为$0$,且所有前缀不小于$0$。

    对于原串处理时的最小前缀如果小于$0$,则必须在原串前加左括号使之合法。

    考虑$DP$,设$dp[i][j]$表示长度为$i$,总和为$j$的括号序列数量,那么$p$的方案数为$dp[i][j]$,$q$的方案数为$dp[n-m-i][j-a]$($a$为原串的总和)。

    将其乘积相加即为答案。

    时间复杂度:$Theta((n-m)^2)$。

    期望得分:$100$分。

    实际得分:$100$分。


    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    const int mod=1000000007;
    int n,m;
    char ch[100001];
    int res,minn;
    long long dp[2001][2001],ans;
    int main()
    {
    	scanf("%d%d%s",&n,&m,ch+1);
    	for(int i=1;i<=m;i++)
    	{
    		if(ch[i]=='(')res++;
    		else res--;
    		minn=min(minn,res);
    	}
    	dp[0][0]=1;
    	for(int i=1;i<=n-m;i++)
    		for(int j=0;j<=i;j++)
    		{
    			dp[i][j]=dp[i-1][j+1];
    			if(j)dp[i][j]=(dp[i][j]+dp[i-1][j-1])%mod;
    		}
    	for(int i=0;i<=n-m;i++)
    		for(int j=0;j<=i;j++)
    			if(j+res<=n-m&&j+minn>=0)
    				ans=(ans+dp[i][j]*dp[n-m-i][res+j]%mod)%mod;
    	printf("%lld",ans);
    	return 0;
    }
    

    rp++

  • 相关阅读:
    [HDU2866] Special Prime (数论,公式)
    [骗分大法好] 信息学竞赛 骗分导论(论文搬运)
    flayway数据库管理
    RabbitMQ的基本概念与原理
    springboot+ideal实现远程调试
    盘点总结
    mysql查看进程命令
    Java字符串正则文本替换
    springboot代码级全局敏感信息加解密和脱敏方案
    使用PMD进行代码审查
  • 原文地址:https://www.cnblogs.com/wzc521/p/11670426.html
Copyright © 2011-2022 走看看