C++消消乐
博主推荐
1、C++专栏
2、Python专栏
- 蓝桥杯python选拔赛真题详解
- 蓝桥杯python省赛真题详解
- 蓝桥杯python国赛真题详解
- 信息素养大赛python编程挑战赛
- python等级一级真题解析【电子学会】
- python等级二级真题解析【电子学会】
- python等级三级真题解析【电子学会】
一、题目要求
1、编程实现
小 L 现在在玩一个低配版本的消消乐,该版本的游戏是一维的,一次也只能消除两个相邻的元素。
现在,他有一个长度为 n 且仅由小写字母构成的字符串。我们称一个字符串是可消除的,当且仅当可以对这个字符串进行若干次操作,使之成为一个空字符串。
其中每次操作可以从字符串中删除两个相邻的相同字符,操作后剩余字符串会拼接在一起。
小 L 想知道,这个字符串的所有非空连续子串中,有多少个是可消除的。
2、输入输出
输入描述:
输入的第一行包含一个正整数 n,表示字符串的长度。
输入的第二行包含一个长度为 n 且仅由小写字母构成的的字符串,表示题目中询问的字符串。
输出描述:输出一行包含一个整数,表示题目询问的答案。
输入样例:
8
accabccb
输出样例:
5
【样例解释】
一共有 5 个可消除的连续子串,分别是 cc
、acca
、cc
、bccb
、accabccb
。
【数据范围】
对于所有测试数据有:1≤n≤2×106,且询问的字符串仅由小写字母构成。
测试点 | n≤ | 特殊性质 |
---|---|---|
1∼5 | 10 | 无 |
6∼7 | 800 | 无 |
8∼10 | 8000 | 无 |
11∼12 | 2×10^5 | A |
13∼14 | 2×10^5 | B |
15∼17 | 2×10^5 | 无 |
18∼20 | 2×10^6 | 无 |
特殊性质 A:字符串中的每个字符独立等概率地从字符集中选择。
特殊性质 B:字符串仅由 a
和 b
构成。
二、算法分析
- 从给定题目的初步分析可以看出,本题要求的是能消除的个数。
- 策略1(PTS50):由于是要进行两两消除,所以需要检查字符串的所有非空连续子串,判断每个子串是否可消除。如果一个子串可以通过反复删除相邻相同字符最终变为空,则它是可消除的。
- 可以使用一个栈来模拟起始位置对应的字母,遍历子串的字符,当栈非空且栈顶字符与当前字符相同时,弹出栈顶(表示消除);否则,将当前字符压入栈。
- 但是这种方法当n比较大的时候会出现超时
- 策略2(PTS100):仔细分析会发现可消除的子串具有递归结构。如果一个子串可消除,那么它可以被分解为更小的可消除子串的组合。所以可以使用贪心+动态规划算法进行实现。
- 定义dp[i]:表示在第i个位置能够消除的的子串数量,同时用一个数组pr记录当前第i个字符前一次出现的位置;如果pr[i]=j,表示s[j]和s[i]可以消除,同时s[j到i]之间也是可以消除的。
- 查找的时候如果当前位置
i
的字符与前一个位置i-1
不同,则跳到pr[i-1]-1
继续尝试匹配,直到找到对应字符或者无法匹配
三、程序编写
方法1
#include <bits/stdc++.h>
using namespace std;
int main(){
int n;
cin >> n;
string s;
cin >> s;
while(s.length() != n)
cin >> s;
long long ans = 0;
for (int i = 0; i < n; i++) {
vector<char> st;
for (int j = i; j < n; j++) {
if (!st.empty() && st.back() == s[j])
st.pop_back();
else
st.push_back(s[j]);
if (st.empty())
ans++;
}
}
cout << ans << endl;
return 0;
}
方法2
#include <bits/stdc++.h>
using namespace std;
const int N = 2e6 + 6;
int dp[N], pr[N];
int main() {
int n;
string s;
cin >> n >> s;
long long res;
for (int i = 0; i < n; ++i) {
pr[i] = i - 1;
while (pr[i] >= 0 && s[pr[i]] != s[i])
pr[i] = pr[pr[i]] - 1; //匹配字符的起始位置的前一个位置
if (pr[i] > 0)
dp[i] = dp[pr[i] - 1] + 1;
else dp[i] = (pr[i] == 0);
res += dp[i];
}
cout << res << endl;
return 0;
}
本文作者:小兔子编程 作者首页:小兔子编程-CSDN博客
四、运行结果
8
accabccb
5
4
aaaa
4
五、考点分析
难度级别:难,这题相对而言有一定难度,具体主要考察如下:
- 分析题目,找到解题思路
- 掌握模拟算法的原理和使用方法
- 学会字符串或者字符数组的使用
- 学会贪心算法、动态规划算法的原理及应用
- 能够准确分析出字符消除匹配的机智和跳转思路
- 学会STL 容器的灵活运用:尤其是map和vector的原理和使用
- 学会数学建模能力以及数学运算与逻辑处理能力
- 学会循环语句的熟练使用和分支语句的的控制处理(for、if)
- 学会调试和校对程序设计与逻辑的完整性
- 学会分析题目,算法分析,将复杂问题模块化,简单化,从中找到相应的解题思路
- 充分掌握数组定义和使用、分支语句、循环语句和动态规划算法的应用
PS:方式方法有多种,小朋友们只要能够达到题目要求即可!