Bootstrap

切割01串(牛客小白月赛98)

题意:

给三个整数n,l,r,和一个字符串s,满足l<=|c0-c1|<=r就可以切成字符串a和字符串b,c0为字符串a左侧出现0的次数,c1为字符串b右侧出现1的次数,求最多切割次数

知识点:区间dp

分析:先用前缀和求出数组c1和c0,假设我们在k点进行切割,就可以每次更新dp[l][r],先算出左区间[l,k]的0的个数为c00=c0[k]-c0[l-1],算出右区间[k+1,r]的1的个数为c11=c1[r]-c1[k],符合条件的每次更新区间dp,核心代码dp[l][r]=max(dp[l][r],1+dp[l][k]+dp[k+1][r])。

#include<bits/stdc++.h>
using namespace std;
int dp[510][510],c0[510],c1[510];
int main(){
    int n,L,R;cin>>n>>L>>R;string s;cin>>s;
    for(int i=1;i<=n;i++){
        c1[i]=c1[i-1];
        c0[i]=c0[i-1];
        if(s[i-1]=='1')c1[i]++;
        else c0[i]++;
    }
    for(int len=1;len<=n;len++){
        for(int l=1;l<=n;l++){
            int r=l+len-1;
            if(r>n)break;
            for(int k=l;k<r;k++){
                int c00=c0[k]-c0[l-1];
                int c11=c1[r]-c1[k];
                if(abs(c00-c11)>=L&&abs(c00-c11)<=R){
                    dp[l][r]=max(dp[l][r],dp[l][k]+dp[k+1][r]+1);
                }
            }
        }
    }
    cout<<dp[1][n];
}

;