题目链接:C. The Monster
题目大意
给你一个括号序列,包括()?三个字符,其中?可以代替()中的任意一个,求有多少区间[L, R],使得[L, R]是合法的括号序列。
思路
判断一个括号序列是否合法,必须保证(和)的数量相等,并且从左往右的过程中,)的数量一定一直小于等于(的数量,否则多余的)之后永远无法匹配。
从左往右判断一遍,如果)的数量大于(和?的数量,说明之后那个多余的)再也无法消除了,剩下的都不合法,这时直接break;再从右往左同样地判断一遍,两遍都符合条件的区间就是合法的,++ans。
代码
GNU C++14 Accepted 156 ms 142800 KB
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;
const int maxn = 6000;
char s[maxn];
int c[maxn][maxn];
int main()
{
cin >> s;
int len = strlen(s);
int ans = 0;
for(int l=0; l<len; ++l)
{
int cnt[3] = {0, 0, 0};
for(int r=l; r<len; ++r)
{
if(s[r] == '(') ++cnt[0];
else if (s[r] == ')') ++cnt[1];
else ++cnt[2];
if(cnt[1] > cnt[0]+cnt[2]) break;
int x = abs(cnt[0]-cnt[1]);
if(x<=cnt[2] && (cnt[2]-x)%2==0) c[l][r]++;
}
}
for(int r=len-1; r>=0; --r)
{
int cnt[3] = {0, 0, 0};
for(int l=r; l>=0; --l)
{
if(s[l] == '(') ++cnt[0];
else if (s[l] == ')') ++cnt[1];
else ++cnt[2];
if(cnt[0] > cnt[1]+cnt[2]) break;
int x = abs(cnt[0]-cnt[1]);
if(x<=cnt[2] && (cnt[2]-x)%2==0) c[l][r]++;
if(c[l][r] == 2) ++ans;
}
}
cout << ans << endl;
return 0;
}