2019年ccpc女生赛重现赛题解F

2019年ccpc女生赛重现赛题解F
题目:
String
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 6 Accepted Submission(s): 6

Problem Description
wls 有一个长度为 n 的字符串,每次他可以将一个长度不大于 l 的子串修改成同一种字母,问至少修改多少次可以使字符串最多含有 k 段。
连续的只含同 一种字母的子串被称为一段。比如说, aaabbccaaa 共含有 4 段。

Input
第一行三个整数 n,l,k。
第二行一个字符串。
1 ≤ n ≤ 100, 000
1 ≤ l ≤ 100, 000
1 ≤ k ≤ 10

Output
一行一个数表示答案。

Sample Input

3 1 1
bab

Sample Output

1


思路:dp。

AC代码:

#include
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dep(i,a,b) for(int i=(a);i>=(b);--i)
#define pb push_back
typedef long long ll;
const int maxn=(int)1e5+100;
const int mod=(int)1e9+7;
const int INF=0x7fffffff;
int n,l,k,dp[maxn][11][27];
char str[maxn];
void init()
{
    memset(dp,0x3f3f3f3f,sizeof(dp));
    for(int j=0;j<=k;j++)
	{
		for(int c=0;c<=26;c++)
		{
			dp[0][j][c]=0;
		}
	 } 
    //rep(j,0,k) rep(c,0,26) dp[0][j][c]=0;
}
void solve()
{
    init();
    scanf("%s",str+1);
    for(int i=1;i<=n;i++)
	{
        for(int j=1;j<=k;j++)
		{
            for(int c=0;c<=25;c++)//最后一个是0到25,一共26个数字 
			{
				//dp[i][j][k]就是到第i个字符已经有了j段并且最后一个字符为k 
                if(str[i]==c+'a') dp[i][j][c]=dp[i-1][j][c];
                else dp[i][j][c]=dp[i-1][j-1][c];
                if(i-l<1)//左端点从1开始 
				{
                    dp[i][j][c]=min(dp[i][j][c],dp[1][j][c]+1); 
                    dp[i][j][c]=min(dp[i][j][c],dp[1][j-1][26]+1);
                }
                else
				{
                    dp[i][j][c]=min(dp[i][j][c],dp[i-l][j][c]+1);
                    dp[i][j][c]=min(dp[i][j][c],dp[i-l][j-1][26]+1);
                }
                dp[i][j][26]=min(dp[i][j][26],dp[i][j][c]);

                // else{
                //     rep(cc,0,25) dp[i][j][c]=min(dp[i][j][c],dp[i-l][j-1][cc]+1);
                //     dp[i][j][c]=min(dp[i][j][c],dp[i-l][j][c]+1);
                // }
            }
        }
    }
    printf("%d\n",dp[n][k][26]);
}
int main()
{
    while(~scanf("%d%d%d",&n,&l,&k)) solve();
}

你可能感兴趣的:(动态规划)