刪除子串 --牛客競賽 DP

鏈接:https://acm.nowcoder.com/acm/problem/15362
來源:牛客網
 

題目描述

給你一個長度爲n且由a和b組成的字符串,你可以刪除其中任意的部分(可以不刪),使得刪除後的子串“變化”次數小於等於m次且最長。
變化:如果a[i]!=a[i+1]則爲一次變化。(且新的字符串的首字母必須是'a')
如果初始串全爲b,則輸出0。

輸入描述:


 

第一行輸入兩個數n,m。(1 <= n <= 10^5,0 <= m <= 10)

第二行輸入一行長度爲n且由a和b組成的字符串

輸出描述:

輸出一個數字表示最長長度

示例1

輸入

複製

8 2
aabbabab

輸出

複製

6

說明

原串可以變成aabbbb,只改變了一次,且長度最長。

思路:dp[i][j]表示前i個字符變化j次的最長長度。當我們到第i個字符時,如果上一個取的字符和本次的字符一樣,那麼我們肯定取這個字符,那麼就有轉移方程:dp[i][j]=dp[i-1][j]+1;如果上一個取的字符和本次的字符不一樣,我們可以取,也可以不取,取的時候轉移方程:dp[i][j]=dp[i-1][j-1]+1;不取的時候轉移方程:dp[i][j]=dp[i-1][j],兩者取最大即可。爲了當前狀態記錄取了啥,我們可以用pre[i][j]記錄當前取的字符。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;
char s[maxn],a[maxn],pre[maxn][12];
int dp[maxn][12];
int main()
{
	int n,m,flag=0,cnt=0,cont=0;
	scanf("%d%d",&n,&m);
	scanf("%s",s+1);
	for(int i=1;i<=n;i++)
	{
		if(s[i]=='b'&&flag==0) continue;
		flag=1;
		a[++cnt]=s[i];
	}
	if(cnt==0)
	{
		puts("0");
		return 0;
	}
	for(int i=1;i<=cnt;i++)
	{
		if(a[i]=='a') cont++;
		dp[i][0]=cont;
		pre[i][0]='a';
	}
	for(int i=2;i<=cnt;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(a[i]==pre[i-1][j])
			{
				dp[i][j]=dp[i-1][j]+1;
				pre[i][j]=pre[i-1][j];
			}
			else 
			{
				if(dp[i-1][j]>dp[i-1][j-1]+1)
				{
					dp[i][j]=dp[i-1][j];
					pre[i][j]=pre[i-1][j];
				}
				else
				{
					dp[i][j]=dp[i-1][j-1]+1;
					pre[i][j]=a[i];
				}
			}
		}
	}
	int ans=0;
	for(int i=0;i<=m;i++) ans=max(ans,dp[cnt][i]);
	printf("%d\n",ans);
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章