「枚举」破碎的项链
本题为1月8日22寒假集训每日一题题解
题目来源:(未知)
题面
题目描述
你有一条由N个红色的,白色的,或蓝色的珠子组成的项链(3<=N<=350),珠子是随意安排的。这里是n=29的两个例子:
第一和第二个珠子在图片中已经被作记号。
图片A中的项链可以用下面的字符串表示:
brbrrrbbbrrrrrbrrbbrbbbbrrrrb .
假如你要在一些点打破项链,展开成一条直线,然后从一端开始收集同颜色的珠子直到你遇到一个不同的颜色珠子,在另一端做同样的事(颜色可能与在这之前收集的不同)。确定应该在哪里打破项链来收集到最大多数的数目的子。
举例来说,在图片A中的项链,可以收集到8个珠子,在珠子9和珠子10或珠子24和珠子25之间打断项链。在一些项链中,包括白色的珠子如图片B所示。当收集珠子的时候,一个被遇到的白色珠子可以被当做红色也可以被当做蓝色。
表现项链的字符串将会包括三符号r,b和w。写一个程序来确定从一条被供应的项链最大可以被收集珠子数目。
输入
第一行,N,珠子的数目
第二行,一串度为N的字符串,每个字符是r,b或w。
输出
单独的一行包含从被供应的项链可以被收集的珠子数目的最大值。
样例输入
29
wwwbbrwrbrbrrbrbrwrwwrbwrwrrb
样例输出
11
思路分析
本题的数据量只有350,所以可以直接枚举
每一个分割点,然后记录最大的情况既可.
由于此处的珠子是一个环,所以我们可以在输入的字符串前后拼接两个一模一样的字符串,来模拟环的情况(这是在数据是环形时的常用技巧).不过这里要注意,此处的拷贝行为可能会导致后续统计左右段的时候出现区间重叠,此时最终统计出来的答案会比一个环的长度要长.不过既然能够重叠,就证明两边加起来可以走完整个环,此时把答案赋值成环的长度即可.
此处唯一的难点可能是对白色的特判处理,具体的看下面的参考代码即可,只要细心地考虑所有可能的情况就可以了.
参考代码
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3, "Ofast", "inline")
#include <iostream>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
int n;
cin >> n;
string s;
cin >> s;
s += s + s; // 前后拼接两个一模一样的字符串来模拟环
int res = 0;
for (int i = n; i < 2 * n; i++) // 枚举每一个分割点
{
int len = 0; // 当前结果
int l = i - 1; // 左段起始下标
int r = i; // 右段起始下标
char cL = s[l]; // 左段起始颜色
char cR = s[r]; // 右段起始颜色
// 左指针不断左移,直到越界或遇到不同的颜色为止
// 如果起始颜色是白色,由于白色可以染成任何颜色,当前颜色是什么都可以移动,不过在移动后要把起始颜色更新成当前的颜色
// 如果当前遇到的颜色是白色,由于白色可以染成任何颜色,所以可以当做与起始颜色一致,可以继续移动
while (l >= 0 && (s[l] == cL || cL == 'w' || s[l] == 'w'))
{
len++;
l--;
if (cL == 'w') // 起始颜色是白色,需要把起始颜色更新成当前的颜色
{
cL = s[l];
}
}
// 右指针不断右移,直到越界或遇到不同的颜色为止
// 对白色的处理同理
while (r < 3 * n && (s[r] == cR || cR == 'w' || s[r] == 'w'))
{
len++;
r++;
if (cR == 'w') // 起始颜色是白色,需要把起始颜色更新成当前的颜色
{
cR = s[r];
}
}
len = min(len, n); // 如果出现区间重叠(当前结果超过n),需要把当前结果改为n
res = max(len, res); // 记录最大值
}
cout << res << "\n";
return 0;
}
"正是我们每天反复做的事情,最终造就了我们,优秀不是一种行为,而是一种习惯" ---亚里士多德
这里是浙江理工大学22届ACM集训队的成员一枚鸭!
本文首发于博客园,作者:星双子,除了我自己的转载请注明原文链接:https://www.cnblogs.com/geministar/p/zstu22_1_8.html