题意:
给你一个字符串和整数k,保证字符串的长度为k的整数倍, 要求将该字符串每k个一组进行重排, 求最后的最小块数
分析:
状态定义: dp[i][j]表示第i段中以字母j-1+‘a’结尾的最小块数
可先分别计算出各个段的块数, 然后根据前后段的字母是否相同进行更新
#include
#include
#include
using namespace std;
const int inf = 0x3f3f3f3f;
int dp[1010][30], cnt[1010][30], sum[1010];
int t, k;
char s[1010];
int main() {
scanf("%d", &t);
while(t--) {
scanf("%d%s", &k, s+1);
int n = strlen(s + 1);
memset(cnt, 0, sizeof(cnt));
memset(sum, 0, sizeof(sum));
for(int i=1; i<=n/k; i++)
for(int j=1; j<=k; j++)
cnt[i][s[(i-1)*k+j]-'a'+1]++;
for(int i=1; i<=n/k; i++)
for(int j=1; j<=26; j++)
if(cnt[i][j])
sum[i]++;
memset(dp, inf, sizeof(dp));
for(int i=1; i<=26; i++)
dp[1][i] = cnt[1][i] ? sum[1] : inf;
for(int i=2; i<=n/k; i++)
for(int j=1; j<=26; j++)
if(cnt[i-1][j]) {
for(int k=1; k<=26; k++)
if(cnt[i][k]) {
if(j == k) {
if(sum[i] == 1)
dp[i][k] = min(dp[i][k], dp[i-1][j]);
else
dp[i][k] = min(dp[i][k], dp[i-1][j] + sum[i]);
}
else if(cnt[i][j])
dp[i][k] = min(dp[i][k], dp[i-1][j] + sum[i] - 1);
else
dp[i][k] = min(dp[i][k], dp[i-1][j] + sum[i]);
}
}
int ans = inf;
for(int i=1; i<=26; i++)
ans = min(ans, dp[n/k][i]);
printf("%d\n", ans);
}
return 0;
}