题意
这个题中出现的字符串只能有a, b, c
三个字母构成。如果一个字符串里不存在一个子串,既是回文串又有长度大于等于2
,那么这个串就很漂亮。
给一个长为n
的字符串,有m
次询问,每次询问[l,r]
这个区间的字符串,至少需要改变几个字符,才能把它变成一个好看的字符串。
思路
关键点:一个漂亮的字符串,其实任意三个相邻字符都两两不相同。
证明:思考这样的一个问题,假如一个字符串里有bab
这个子串,显然这个子串他是回文的,还长度大于等于2,这会导致这整个字符串都不漂亮。还可以多举几个例子验证一下。
那么,对于一个漂亮的字符串而言,这个字符串他是怎样构成的?其实就是a,b,c
这三个字母的排列组合问题,它的构成只能是这样的:
- abc形:abcabcabcabcabc...
- acb形:acbacbacbacbacb...
- bac形:bacbacbacbacbac...
- bca形:bcabcabcabcabca...
- cab形:cabcabcabcabcab...
- cba形:cbacbacbacbacba...
所以,这个题的思路就是,对于任何一个要询问的字符串,跟这六种情况比一比,看看不一样的字符有几个,这六种里最少的那个就是答案了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<string>
const int N = 2e5 + 233;
using namespace std;
int n, m;
char str[N], s[7][3] = {
{'a', 'b', 'c'},
{'a', 'c', 'b'},
{'b', 'a', 'c'},
{'b', 'c', 'a'},
{'c', 'a', 'b'},
{'c', 'b', 'a'}
};
int fuck[N][6];
void init() {
//这里对str预处理,处理出6种情况下不一样字符个数的前缀和数组(fuck数组)
for (int k = 0; k < 6; k++) {
for (int i = 1, p = 0; i <= n; i++, p = (p + 1) % 3) {
if (str[i] != s[k][p]) fuck[i][k]++;
fuck[i][k] += fuck[i - 1][k];
}
}
}
int solve(int l, int r) {
int ans = 0x3f3f3f3f;
for (int k = 0; k < 6; k++) {
ans = min(ans, fuck[r][k] - fuck[l - 1][k]);
}
return ans;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
cin >> n >> m;
cin >> (str + 1);
init();
int l, r;
while (m--) {
cin >> l >> r;
cout << solve(l, r) << '\n';
}
return 0;
}