2023牛客寒假算法集训营-本题主要考察了dp

题目

有一个由0和1组成的长为n的字符串,其中有m个字符是1,对于一个长度恰好为3的子区间,如果字符1的数量比0大,就是一个坏区间,你可以自由调整0和1的位置,但数量不能改变,求坏区间总数最少的字符串中有几个坏区间 。

思路

如果我们贪心地想不让坏区间出现,我们就能构造出一个100100100100……由100为一个单位组成的字符串,如果这时候m个1能全部放完,答案自然就是0,如果不能放完,我们要想办法将字符串里的某些0替换成1,使得增加的坏区间最少。

再继续分析,对于一个0变成一个1,那么受影响的自然是以这个数字为开头,为中间,为末尾的三个子区间。因此我们先操作右边界和左边界的0,因为左边界的0不存在以它为末尾的长度恰好为3的子区间,右边界的0不存在以它为开头、以它为中间的长度恰好为3的子区间。剩下的只要从左到右依次地将0改为1就可以了,因为相靠的两个0变成1会产生重合的受影响的子区间。对于具体计算,我们发现从左到右依次将0改成1,对于一个“100”单元,由于前一个单元的影响,第一个0会增加两个坏区间(以它为中间,以它为开头),由于第一个0的影响,第二个0会增加一个坏区间(以它为开头)。然后问题就解决了。

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn=1005;
int num[2]={2,1};
char str[maxn];
int main(){
    int n,m;
    cin>>n>>m;
    if(n==m&&n>=3){
    	cout<<n-2;
    	return 0;
	} 
	else if(n<3){
		cout<<"0";
		return 0;
	}
    for(int i=0;i<n;i++){
        if(i%3==0){
            str[i]='1';
            m--;
        }
    }
    if(m<=0){
        cout<<"0"<<endl;
        return 0;
    }
    int ans=0,flag=0;
    for(int i=n-1;i>=0;i--){
        if(str[i]=='1'||m<=0)break;
        str[i]='1';
        m--;
        ans++;
    }
    if(m<=0){
        cout<<ans;
        return 0;
    }
    for(int i=0;i<n;i++){
        if(m<=0)break;
        if(str[i]=='1')continue;
        str[i]='1';
        ans+=num[flag];
        flag=!flag;
        m--;
    }
    cout<<ans;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值