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--,然后求删除该位后的答案,然后将该位的字符变换奇偶性即可.