思路;用dp[i][j]表示到第i组末尾为字母j块的最小值,那么dp[i][j] = min(dp[i][j], dp[i-1][l] + f[i] - 1), 第i组和第i-1组含有字母l,并且l和j不同,否则dp[i][j] = min(dp[i][j],dp[i-1][l] + f[i]).f[i]为每组的不同字母数。
#include<cstdio>
#include<set>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<map>
#include<queue>
#include<vector>
#include<string>
#include<sstream>
#include<cmath>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 100 + 20;
const double EPS = 1e-5;
const int mod = 1e8 + 7;
typedef unsigned long long ull;
typedef long long ll;
int dx[] = {0, 0, -1, 1, -1, -1, 1, 1};
int dy[] = {1, -1, 0, 0, -1, 1, -1, 1};
int a, b;
int gcd(int x, int y){
return !y ? x : gcd(y, x % y);
}
int k;
char s[1010];
int f[1010];
int d[1010][27];
int dp[1010][27];
int main(){
int T;
scanf("%d", &T);
while(T--){
scanf("%d%s", &k, s);
int len = strlen(s);
memset(f, 0, sizeof f);
memset(dp, INF, sizeof dp);
memset(d, 0, sizeof d);
int t = 0;
int n = len / k;
for(int i = 1; i <= len / k; ++i){
int cnt = 0;
for(; t < i * k; ++t){
int c = s[t] - 'a';
if(d[i][c] == 0){
cnt++;
d[i][c]++;
}
else d[i][c]++;
}
f[i] = cnt;
}
for(int i = 0; i < 26; ++i) dp[0][i] = 0;
for(int i = 1; i <= n; ++i){
for(int j = 0; j < 26; ++j){
for(int l = 0; l < 26; ++l){
if(d[i][l] && d[i - 1][l] && (l != j || l == j && f[i] == 1)){
dp[i][j] = min(dp[i][j], dp[i - 1][l] + f[i] - 1);
}
else
dp[i][j] = min(dp[i][j], dp[i - 1][l] + f[i]);
}
}
}
int ans = INF;
for(int i = 0; i < 26; ++i)
ans = min(ans ,dp[n][i]);
printf("%d\n", ans);
}
}
/*
2
5 helloworld
7 thefewestflops
*/
431

被折叠的 条评论
为什么被折叠?



