题意:求将一个字符串每k个分为一块,每个块中的字符可以随意排列,连续的相同的字符算作一个chunks,问一个串中最少有几个chunks。
思路:每个块中的chunks就是这个块中不同字符的个数,因为每个块的第一个字符也可以和上一个块的字符构成连续的相同的字符,所以我们用f[i][j]表示第i块以第j个字符作为最后一个的最少的chunks,这个表示还是从学长的题解看的,那么我们枚举前一个块的最后一个字符和当前块的最后一个字符,只要他们不相等的话,那么只要这两个块有出现相同的字符,就可以减去一,当然这里要有当当前的卡的chunks是1 的特判,否则就要加上这个块的所有chunks
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 1010;
const int INF = 0x3f3f3f3f;
int k;
char str[MAXN];
int f[MAXN][MAXN];
bool vis[130];
int main(){
int t;
scanf("%d",&t);
while (t--){
scanf("%d %s",&k,str);
int len = strlen(str);
memset(f,INF,sizeof(f));
for (int i = 0; i < len/k; i++){
int chunks = 0;
memset(vis,0,sizeof(vis));
for (int j = i*k; j <= (i+1)*k-1; j++)
vis[str[j]] = true;
for (int j= 'a'; j <= 'z'; j++)
if (vis[j])
chunks++;
if (i == 0){
for (int j = 0; j < k; j++)
f[i][j] = chunks;
continue;
}
for (int j = 0; j < k; j++){
int rear = i * k + j;
for (int l = 0; l < k; l++){
int pre = (i-1) * k + l;
if (vis[str[pre]] && (chunks == 1 || str[pre] != str[rear]))
f[i][j] = min(f[i][j],f[i-1][l]+chunks-1);
else f[i][j] = min(f[i][j],f[i-1][l]+chunks);
}
}
}
int ans = INF;
for (int i = 0; i < k; i++)
ans = min(ans,f[len/k-1][i]);
printf("%d\n",ans);
}
return 0;
}