Codeforces 676C - Vasya and String
题目原址
[http://codeforces.com/contest/676/problem/C]
题意
给一个 n 个字符(只含 a 或 b )的字符串,通过改变当中的 k 个字符( a 改为 b , b 改为 a ),求改变后字符串的连续子序列(只含 a ,或者只含 b )的最大长度。
题解
尺取法
用 两个可移动的端点 去量所给定的数组(字符串是char数组),通过给定的条件来 更变两个端点的位置来搜寻最值。
在这道题中,我们可以分两种情况来搜寻最长连续子序列的长度,这个子序列 1. 只含a, 2. 只含b。
对于任意其中一种情况,操作相同,下面以找最长 a 连续子序列长度为例:
- 初始化左右端点为0,答案为0,计数器(记录更改字符的数量)为0
- 判断右端点是否小于 n ,是进入第3步,否则进入第9步
- 判断该字符是不是 a ,是进入第4步,否则进入第5步
- 该字符是 a ,继续扩长,右端点+1,去第8步
- 判断是否还能改变该 b 为 a,(计数器是否小于 k ),能进入第6步,否则第7步
- 能改继续改,计数器+1,右端点+1,去第8步
- 不能改了就将最左端的 b 去掉,使得现在这个 b 能够更改。即:循环如果左端点的值是 a ,则左端点+1,否则退出循环,且左端点+1,右端点+1,然后去第8步
- 取新的答案为原来答案和现在答案(右-左+1)的最大值,然后回到第2步。
- 现在答案就是最长 a 的连续子序列的长度
实现
#include <stdio.h>
#include <algorithm>
using namespace std;
const int maxn = 100005;
int n, k;
char s[maxn];
int solve(char c) {
int l = 0;
int r = 0;
int cnt = 0;
int ans = 0;
while (r < n) {//观察上面步骤发现无论如何右端点总是要+1,故把所有r++合成1个
if (s[r] != c)//不是所要字符的话
if (cnt >= k)//如果不能更改了的话
while (s[l++] == c)//左端点仍然是c时
continue;
else
cnt++;
r++;
ans = max(ans, r - l);
}
return ans;
}
int main() {
scanf("%d%d%s", &n, &k, s);
printf("%d\n", max(solve('a'), solve('b')));
}