NC18413 括号 动态规划
作者:互联网
链接:https://ac.nowcoder.com/acm/problem/18413
来源:牛客网
题目描述
小A有一个只包含左右括号的字符串S。但他觉得这个字符串不够美观,因为它不是一个合法的括号串。一个合法的括号串是这样定义的: 1. ()是合法的括号串 2. 若A是合法的括号串,则(A)则是合法的括号串 3. 若A,B是合法的括号串,则AB也是合法的括号串。小A现在希望删掉S中若干个字符,使得剩下的字符串是一个合法的括号串。小A想知道有多少不同的方案。两个方案是不同的,当且仅当他们删除的位置不同。比如当S是(()时,有两种方案。分别是删掉第一个位置,或是删掉第二个位置。
输入描述:
第一行一个整数n,代表S的长度。
第二行输入n个字符,字符要么是(,要么是)。代表串S。
输出描述:
一行一个整数,代表不同的方案数。答案对10^9+7取模。示例1
输入
复制8 )(()(())
输出
复制30
备注:
20%: n <= 20
40%: n <= 100
60%: n <= 1000
100%: n <= 10000
分析
首先,得确定是哪种DP,这题是计算完全匹配的方案数量,不是选择。但可以是区间DP,或者线性DP。
为什么不是区间DP,而是线性DP?
这道题的数据范围是1e5,n^2 显然不可能,那就只能是线性DP了
线性DP,随着字符串长度的变长,完全匹配的方案是在增加的,不匹配的左括号也是在增加的,不匹配的左括号的数目最多是多少呢?是当前遍历到的字符串长度。什么时候完全匹配的方案会增加呢?遇到右括号的时候。什么时候不匹配的左括号会增加呢?遇到左括号的时候。
假设f[i][j] 表示 遍历到第i个字符,总共有j个不匹配的左括号的方案数。
由于还没遍历数组的时候,是空集,方案合法,所以初值:f[0][0] = 1
当遍历到左括号,不匹配的方案数增加,容易想到状态转移方程式:f[i][j] += f[i-1][j-1]
当遍历到右括号,匹配的方案数增加,容易想到状态转移方程是:f[i][j] += f[i-1][j+1]
更改遍历顺序能够压缩数组成一维:f[j] 表示 遍历到第i个字符,总共有j个不匹配的左括号的方案数
最后输出答案f[0] - 1(去掉空集,由例子知,该方案不合法)
代码
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
const int N = 10005;
const ll mod = 1e9 + 7;
ll f[N]; //表示前i个字符中有j个左括号未配对成功的方案数
int n;
char s[N];
int main()
{
scanf("%d%s",&n,s+1);
f[0] = 1;
for(int i = 1;i<=n;i++) {
if(s[i] == '(') {
for(int j = n;j>=0;j--) {
if(j !=0 ) f[j] = (f[j] + f[j-1]) % mod;
}
} else {
for(int j = 0;j<=n-1;j++) {
f[j] = (f[j] + f[j+1]) % mod;
}
}
}
f[0] -- ;
cout<<f[0]<<endl;
}
标签:方案,遍历,匹配,合法,括号,动态,NC18413,DP 来源: https://www.cnblogs.com/er007/p/16462326.html