版权声明:欢迎大家转载,转载请注明出处 https://blog.csdn.net/hao_zong_yin/article/details/82023386
注意当前块结尾字符若等于前一个块的结尾字符,要判一下当前块的字符总数是否为1
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1010;
const int INF = 0x3f3f3f3f;
int T, k;
char s[maxn];
struct Block {
int cnt;
bool c[26];
}a[maxn];
int dp[maxn][26]; //递推到第i块,当前块以字符j为结尾的最小答案
void solve() {
scanf("%d", &k);
scanf("%s", s);
int n = strlen(s);
for (int i = 0; i < n; i++) {
a[i].cnt = 0;
for (int j = 0; j < 26; j++) a[i].c[j] = 0;
}
for (int i = 0; s[i]; i += k) {
for (int j = 0; j < k; j++) {
a[i/k].c[s[i+j]-'a'] = 1;
}
for (int j = 0; j < 26; j++) if (a[i/k].c[j]) a[i/k].cnt++;
}
n = n / k;
// cout << " ";
// for (int i = 0; i < 26; i++) cout << (char)(i+'a') << " ";
// cout << endl;
// for (int i = 0; i < n; i++) {
// cout << a[i].cnt << ":";
// for (int j = 0; j < 26; j++) cout << a[i].c[j] << " ";
// cout << endl;
// }
for (int i = 0; i < n; i++) for (int j = 0; j < 26; j++) dp[i][j] = INF;
for (int j = 0; j < 26; j++) dp[0][j] = a[0].cnt;
for (int i = 1; i < n; i++) {
for (int j = 0; j < 26; j++) {
if (!a[i].c[j]) continue;
for (int k = 0; k < 26; k++) {
if (!a[i-1].c[k]) continue;
if (a[i].c[k]) {
if (k == j) dp[i][j] = min(dp[i][j], dp[i-1][k] + a[i].cnt - (a[i].cnt == 1));
else dp[i][j] = min(dp[i][j], dp[i-1][k] + a[i].cnt - a[i].c[k]);
}
else dp[i][j] = min(dp[i][j], dp[i-1][k] + a[i].cnt - a[i].c[k]);
}
}
}
int ans = INF;
for (int j = 0; j < 26; j++) ans = min(ans, dp[n-1][j]);
printf("%d\n", ans);
}
int main() {
scanf("%d", &T);
while (T--) solve();
return 0;
}