题解:CF917A The Monster
CF917A 题解
题面
思路
看了下题目,很简单,直接从开头开始爆搜即可,枚举出一种可能,答案就加一。
问题来了,爆搜的过程呢?
容易想到,可以用一个变量 \(sum\) 动态统计当前序列未配对的左括号的数量,对于一个 \(s[i](i\in[1,strlen(s)])\) 有如下两种情况:
- 若 \(s[i]\) 为
(
,则 \(sum\) 加一,表示未配对的左括号数加一。 - 若 \(s[i]\) 为
)
,则 \(sum\) 减一,表示未配对的左括号数减一。
如上是正常情况,接下来要考虑特殊情况:如果 \(s[i]\) 是 ?
呢?容易想到,再用一个 \(num\) 来统计 ?
修改成 )
的个数,接下来同样的,分成两种情况,讨论 ?
是换成 (
还是 )
:
- 若未配对的左括号的数量大于 \(0\),即 \(sum>0\) 时,则把
?
变成)
去和左括号配对。所以是 \(sum-1,num+1\)。 - 否则,
?
变成(
,即 \(sum+1\)。
于是,一个子区间就处理好了,接下来要对这个子区间进行判断,有如下三种情况:
- \(sum<0,num>0\),说明可以把之前的右括号改为左括号,则 \(sum+2\),并且 \(num-1\)。
- \(sum<0,num=0\),则序列违法,无法每对括号都匹配成功。
- \(sum=0\),则这个序列满足条件,\(ans+1\)。
于是,代码基本就可以出来了。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
char s[5005];
int sum,ans,num,len;
//sum是用来记录未配对的左括号的数量。
//ans为答案。
//num统计‘?’可以修改成‘)’的个数。
//len来统计输入序列的长度。
int main(){
cin>>s;
len=strlen(s);//求输入的字符串的长度。
for(int i=0; i<len; i++){//暴力枚举。
sum=0,num=0;//初始化。
for(int j=i; j<len; ++j){
if(s[j]=='(') sum++;//正常情况:为前括号,未配对的左括号数+1。
if(s[j]==')') sum--;//正常情况:未配对的左括号数-1。
if(s[j]=='?'){//特殊情况‘?’,可以为任意符号。
if(sum>0) sum--,num++;
else sum++;
}
if(sum<0&&num) sum+=2,num--;//sum<0且num>0,说明可以把之前的右括号改为左括号,则sum+=2,并num--;。
if(sum<0&&!num) break;//序列违法,无法每对括号配对成功。
if(sum==0) ans++;//sum等于0则答案就多一种,ans++;。
}
}
cout<<ans;
return 0;
}