NC18413 括号 动态规划
链接:https://ac.nowcoder.com/acm/problem/18413
来源:牛客网
题目描述
输入描述:
第一行一个整数n,代表S的长度。
第二行输入n个字符,字符要么是(,要么是)。代表串S。
输出描述:
一行一个整数,代表不同的方案数。答案对10^9+7取模。
备注:
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;
}