#include<bits/stdc++.h>
using namespace std ;
const int N = 2e5+23 ;
//思路:dp
//dp[i][j][k]为处理了1->i。第i个位置为j+'a',最多k段的最小处理数
//1.s[i]==j+'a' 第i位不用修改,则由i-1转移过来,dp[i][j][k] = dp[i-1][j][k]
//2.s[i]!=j+'a' 第i位用修改,贪心,由p=i-l转移,dp[i][j][k]=min(dp[p][j][k],dp[p][c][k-1])+1
//解决:dp[i][c][k]: dp[i][26][k]=min(dp[i][c][k])
//core:1.线性处理,无后效性 ,所以无需dp[i][j][k]=min(dp[i][j][k],...)
//2.总共26个字母,所以dp[位置i][字母][段落]:1-i处理完
//转移过程:第i位要不要修改
//贪心:更改越多越好
int n,l,op ;
char s[N] ;
int dp[N][28][11] ;
void solve()
{
memset(dp,0x3f,sizeof(dp)) ;
for(int j = 0 ; j < 26 ; j++)
{
if(s[1]==j+'a') dp[1][j][1] = 0 ;
else dp[1][j][1] = 1 ;
}
dp[1][26][1] = 0 ;
for(int i = 2 ; i <= n ; i++)
{
for(int j = 0 ; j < 26 ; j++)
{
for(int k = 1 ; k <= op ; k++)
{
if(s[i]==j+'a') dp[i][j][k] = dp[i-1][j][k] ;
else
{
int p = max(1,i-l) ;
dp[i][j][k]=min(dp[p][j][k],dp[p][26][k-1])+1 ;
}
dp[i][26][k] = min(dp[i][26][k],dp[i][j][k]) ;
//printf("dp[%d][%d][%d]=%d\n",i,j,k,dp[i][j][k]) ;
}
}
}
printf("%d\n",dp[n][26][op]) ;
}
int main()
{
scanf("%d%d%d",&n,&l,&op) ;
scanf("%s",s+1) ;
solve() ;
return 0 ;
}
参考: