删除子串(DP)

problem

https://www.nowcoder.com/acm/contest/79/C

给你一个长度为n且由a和b组成的字符串,你可以删除其中任意的部分(可以不删),使得删除后的子串“变化”次数小于等于m次且最长。
变化:如果a[i]!=a[i+1]则为一次变化。(且新的字符串的首字母必须是’a’)
如果初始串全为b,则输出0。

输入描述

第一行输入两个数n,m。(1 <= n <= 105,0 <= m <= 10)
第二行输入一行长度为n且由a和b组成的字符串

输出描述

输出一个数字表示最长长度

输入

8 2
aabbabab

输出

6

说明

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

思路

DP

见注释

代码示例1

#include<bits/stdc++.h>
using namespace std;

int n,m;
const int maxn=1e5+10;
const int inf=0x3f;
//i j 表示长度为i 变化次数不超过j
int a[maxn][12];//以a结尾
int b[maxn][12];//以b结尾

char str[maxn];

int main()
{
    //freopen("in.txt","r",stdin);
    ios::sync_with_stdio(false);
    cin>>n>>m;
    cin>>str;
    memset(b,-inf,sizeof(b));//不能以b开头 即b只能由a更新过来
    for(int i=0;i<n;++i){
        for(int j=0;j<=m;++j){
            a[i+1][j]=a[i][j];//结尾不变的话 先等于了 这个有两种情况变大 ①后面不同  j+1  ② 后面相同直接+1
            b[i+1][j]=b[i][j];
            if(str[i]=='a'){
                for(int j=0;j<=m;++j){
                    a[i+1][j+1]=max(a[i+1][j+1],b[i][j]+1);
                    a[i+1][j]=max(a[i+1][j],a[i][j]+1);
                }
            }
            else{
                for(int j=0;j<=m;++j){
                    if(a[i][j]>0){
                        b[i+1][j+1]=max(b[i+1][j+1],a[i][j]+1);
                    }
                    b[i+1][j]=max(b[i+1][j],b[i][j]+1);
                }
            }
        }
    }
    cout<<max(a[n][m],b[n][m])<<endl;
    return 0;
}

代码示例2

//qls
#include<bits/stdc++.h>
using namespace std;

const int maxn=1e5+10;
int n,m;
char str[maxn];
int dp[maxn][12][2];
int main()
{
    scanf("%d %d %s",&n,&m,str+1);
    for(int i=n;i>=1;--i){
        for(int j=0;j<=m;++j){
            for(int k=0;k<2;++k){
                dp[i][j][k]=max(dp[i+1][j][k],dp[i][j][k]);
                int tk=str[i]-'a',tj=j+(k!=tk);
                if(tj<=m) dp[i][tj][tk]=max(dp[i][tj][tk],dp[i+1][j][k]+1);
            }
        }
    }
    int ans=0;
    for(int i=0;i<=m;++i){
        ans=max(ans,dp[1][i][0]);
    }
    printf("%d\n",ans);
    return 0;
}

为什么我会写出这样的代码

#include<bits/stdc++.h>
using namespace std;

int n,m;
const int maxn=1e5+10;
const int inf=0x3f;

char str[maxn];
char str1[maxn];
int dp[maxn][12];//长度为i 翻转次数最多为j 最长的串的长度
int dfs(int i,int j)
{
    cout<<i<<' '<<j<<endl;
    if(dp[i][j]!=-1) return dp[i][j];
    //边界
    if(j==0) return dp[i][j]=-inf;
    if(i==1) return dp[i][j]=1;
    if(str1[i-1]!=str1[i-2]){
        //删还是不删
        int tp1;
        char tp=str1[i-1];
        str1[i-1]=str1[i];
        if(str1[i-1]==str1[i-2]) tp1=dfs(i-1,j);
        else tp1=dfs(i-1,j-1);
        str1[i-1]=tp;
        return dp[i][j]=max(max(tp1,dfs(i-1,j-1)+1),dp[i][j]);
    }
    else return dp[i][j]=max(dfs(i-1,j)+1,dp[i][j]);
}

int main()
{
    ios::sync_with_stdio(false);
    freopen("in.txt","r",stdin);
    cin>>n>>m;
    cin>>str;

    memset(dp,-1,sizeof(dp));
    int k=n;
    for(int i=0;i<n;++i)
    if(str[i]=='a'){
        k=i;
        break;
    }
    //全b
    if(k==n){
        cout<<0<<endl;
        return 0;
    }
    for(int i=k;i<n;++i) str1[i-k]=str[i];
    //str1 dp  长度n-k
    for(int i=0;i<=m;++i){
        dfs(n-k,i);
    }
    int ans=-inf;
    for(int i=0;i<=m;++i)
        ans=max(ans,dp[n-k][i]);
    cout<<ans+k<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值