【思维题】Codeforces 1555D Say No to Palindromes

题意

这个题中出现的字符串只能有a, b, c三个字母构成。如果一个字符串里不存在一个子串,既是回文串又有长度大于等于2,那么这个串就很漂亮。
给一个长为n的字符串,有m次询问,每次询问[l,r]这个区间的字符串,至少需要改变几个字符,才能把它变成一个好看的字符串。

思路

关键点:一个漂亮的字符串,其实任意三个相邻字符都两两不相同。

证明:思考这样的一个问题,假如一个字符串里有bab这个子串,显然这个子串他是回文的,还长度大于等于2,这会导致这整个字符串都不漂亮。还可以多举几个例子验证一下。

那么,对于一个漂亮的字符串而言,这个字符串他是怎样构成的?其实就是a,b,c这三个字母的排列组合问题,它的构成只能是这样的:

  1. abc形:abcabcabcabcabc...
  2. acb形:acbacbacbacbacb...
  3. bac形:bacbacbacbacbac...
  4. bca形:bcabcabcabcabca...
  5. cab形:cabcabcabcabcab...
  6. 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;
}
上一篇
下一篇