题解:CF917A The Monster

CF917A 题解

题面

原题传送门

思路

看了下题目,很简单,直接从开头开始爆搜即可,枚举出一种可能,答案就加一。

问题来了,爆搜的过程呢?

容易想到,可以用一个变量 \(sum\) 动态统计当前序列未配对的左括号的数量,对于一个 \(s[i](i\in[1,strlen(s)])\) 有如下两种情况:

  1. \(s[i]\)(,则 \(sum\) 加一,表示未配对的左括号数加一。
  2. \(s[i]\)),则 \(sum\) 减一,表示未配对的左括号数减一。

如上是正常情况,接下来要考虑特殊情况:如果 \(s[i]\)? 呢?容易想到,再用一个 \(num\) 来统计 ? 修改成 ) 的个数,接下来同样的,分成两种情况,讨论 ? 是换成 ( 还是 )

  1. 若未配对的左括号的数量大于 \(0\),即 \(sum>0\) 时,则把 ? 变成 ) 去和左括号配对。所以是 \(sum-1,num+1\)
  2. 否则,? 变成 (,即 \(sum+1\)

于是,一个子区间就处理好了,接下来要对这个子区间进行判断,有如下三种情况:

  1. \(sum<0,num>0\),说明可以把之前的右括号改为左括号,则 \(sum+2\),并且 \(num-1\)
  2. \(sum<0,num=0\),则序列违法,无法每对括号都匹配成功。
  3. \(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;
}
posted @ 2025-01-29 15:46  naroto2022  阅读(14)  评论(0)    收藏  举报