题目描述
难度分:1846
输入n(1≤n≤3×105),m(1≤m≤109),k和长为n的字符串s,只包含小写字母o
和x
。
保证至少有一个x
,保证1≤k≤s.count(x)×m。
将s重复m次,得到字符串t。例如abc
重复3次得到abcabcabc
。
请你修改t中的恰好k个x
。修改后,输出t中最长连续o
的长度。
输入样例1
10 1 2
ooxxooooox
输出样例1
9
输入样例2
5 3 4
oxxox
输出样例2
8
输入样例3
30 1000000000 9982443530
oxoxooxoxoxooxoxooxxxoxxxooxox
输出样例3
19964887064
算法
滑动窗口
这个题纯思维难度,想通了写起来就非常简单,不然就坐牢。让s从0索引开始,先遍历一遍s将所有x
的位置都存入pos数组,其长度为cntX。
可以推出一个公式,如果要将前k个x
改成o
,能够得到的最长连续o
的长度为
[kcntX]×n+pos[k%cntX]
其中[.]是对.进行下取整操作,第一项的[kcntX]表示能将多少段完整的s中的所有x
变成o
,将它们都变成o
之后就能有长度为[kcntX]×n的o
。最后还剩下k%cntX个x
要改成o
,它可以产生长度为pos[k%cntX]的o
,即索引pos[k%cntX](不包括)前面的所有位置都可以是o
。
接下来滑动窗口,让k不断递增代入上面的公式,每次只需要减去窗口左端点x
的位置p,就能够得到p+1到当前x
位置的长度,再减去当前x
(减1)就得到了下一个包含k个x
的最大窗口长度,公式为:
[kcntX]×n+pos[k%cntX]−pos[i]−1,pos[i]是上一个窗口左端点x
的位置。
复杂度分析
时间复杂度
相当于遍历了两遍s串规模的数组,时间复杂度为O(n)。
空间复杂度
开辟了一个数组存储s中x
的所有索引,额外空间复杂度为O(n)。
C++ 代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long LL;
const int N = 300010;
int n, m;
LL k;
char s[N];
int main() {
scanf("%d%d%lld", &n, &m, &k);
scanf("%s", s);
vector<int> pos;
for(int i = 0; i < n; i++) {
if(s[i] == 'x') pos.push_back(i);
}
int cntX = pos.size();
LL ans = min((LL)n*m, k/cntX*n + pos[k % cntX]);
for(int i = 0; i < cntX; i++) {
k++;
LL res = min((LL)n*m, k/cntX*n + pos[k % cntX]) - pos[i] - 1;
ans = max(ans, res);
}
printf("%lld", ans);
return 0;
}