题目链接
题意:
有一个长度为 n 的字符串,每次可以将一个长度不大于 l 的子串修改成同一种字母,问至少修改多少次可以使字符串最多含有 k 段。
连续的只含同 一种字母的子串被称为一段。比如说, aaabbccaaa 共含有 4 段
思路:
dp
dp[i][j][k]表示在该字符串中的第i个字母时,将其修改成以j为结尾的,含有k段的最小次数。
dp[i][27][k]表示 在该字符串中的第i个字母时,将其修改成含有k段的最小次数(结尾可以是任何字母)。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100005;
int dp[maxn][30][15], n, l, z;
char a[maxn];
int main()
{
while (~scanf("%d%d%d", &n, &l, &z))
{
memset(dp, 0x3f3f3f3f, sizeof(dp));
scanf("%s", a + 1);
int i, j, k;
for (j = 1; j <= 27; j++)+
{
for (k = 1; k <= z; k++)
{
dp[0][j][k] = 0;
}
}
for (i = 1; i <= n; i++)
{
for (j = 1; j <= 26; j++)
{
for (k = 1; k <= z; k++)
{
if (a[i] - 'a' + 1 == j)
{
dp[i][j][k] = dp[i - 1][j][k];
}
else
{
dp[i][j][k] = dp[i - 1][27][k - 1];
}
if (i - l > 1)
{
dp[i][j][k] = min(dp[i][j][k], dp[i - l][j][k] + 1);
dp[i][j][k] = min(dp[i][j][k], dp[i - l][27][k - 1] + 1);
}
else
{
dp[i][j][k] = min(dp[i][j][k], dp[1][j][k] + 1);
dp[i][j][k] = min(dp[i][j][k], dp[1][27][k - 1] + 1);
}
dp[i][27][k]=min(dp[i][27][k],dp[i][j][k]);
}
}
}
printf("%d\n",dp[n][27][z]);
}
return 0;
}