鏈接: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;
}