cf973Div3E

https://codeforces.com/contest/2008/problem/E

using ll = long long;

void solve() {
    int n;
    std::cin >> n;
    std::string s;
    std::cin >> s;
    int ans = n;
    //_____________________________
    //_____________________________
    //首先将奇数位置和偶数位置分开看
    int cnt[2][26]{};
    for (int i = 0; i < n; i++) {
        //cnt[i][j],i表示出现的位置,0表示偶数,1表示奇数,j表示出现的哪一个字符,cnt[i][j]表示出现的次数
        cnt[i % 2][s[i] - 'a']++;
    }
    //如果字符串是偶数
    if (n % 2 == 0) {
        //答案首先是n-在偶数中出现最多次的字符,和在奇数中出现最多次的字符
        ans = n - *std::max_element(cnt[0], cnt[0] + 26) - *std::max_element(cnt[1], cnt[1] + 26);
    }
    //这个for循环是针对奇数的,奇偶中的两种数量最多的字符和一定只会越来越小,因为他们加和不变,且在                    
    //不断删除
    //删掉字符i,那么该位(奇数位或者偶数位)的该字符就要--,紧接着,后面的
    for (int i = n - 1; i >= 0; i--) {
        //问题是怎么得到删掉字符i后i后面的字符奇偶性要发生变化,
        //首先从最后一个字符开始,先假设删掉它,然后求删掉该字符后的答案
        cnt[i % 2][s[i] - 'a']--;
        if (n % 2 == 1) {
            ans = std::min(ans, n - *std::max_element(cnt[0], cnt[0] + 26) - *std::max_element(cnt[1], cnt[1] + 26));
        }
        //在之后的操作中,该位的字符都会变换奇偶性,所以直接变换奇偶性即可
        cnt[(i + 1) % 2][s[i] - 'a']++;
    }
    std::cout << ans << "\n";

}


int main() {
    std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
    int t;
    std::cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}

注意到从最后一位开始向前枚举第i个位置时,在之后的枚举中如i-1,i-2,i-3等等i的奇偶性变化是永久的,因为i永远在i-1,i-2,i-3的右边,所以每当删除i左边的位置时,总会让i奇偶性发生变化.所以执行一下操作,从最后一个字符开始,首先让该位的cnt--,然后求删除该位后的答案,然后将该位的字符变换奇偶性即可.

你可能感兴趣的:(codeforces)