小红的01连续段(二分或者dp)

链接:https://ac.nowcoder.com/acm/contest/69695/B
来源:牛客网

小红定义一个01串的“连续段”为:连续相同字符的极大长度。例如:"110001111"有一个长度为2的连续段,有一个长度为3的连续段,有一个长度为4的连续段。
小红拿到了一个01串,但其中有一些字符不可见了(用'?'表示)。小红想知道,这个01串的连续段长度的最大值最多能达到多少?
输入描述:
一个仅由'0'、'1'、'?'组成的字符串,长度不超过200000。
输出描述:
一个正整数,代表连续段长度的最大长度。

示例1
输入
1?0?1?
输出
3
说明
该字符串可以是"100011",最大的连续段长度为3。

二分

这个答案可以用二分+前缀和解决。sum[i]表示前i个1的个数,然后g[i]表示前i个?的个数,然后我们对答案进行二分,假设二分的答案是x,我们只需要看看全部的长度为x的区间中1的个数+?的个数,或者0的个数+?的个数是否等于区间x

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=1e6+100;
char a[maxn]; 
int sum[maxn];
int g[maxn];
int len;
int judge(int x){
	for(int i=1,j=x;j<=len;i++,j++){
		int x1=sum[j]-sum[i-1];
		int x2=g[j]-g[i-1];
		int x0=x-x1-x2;
		if(x1+x2==x||x2+x0==x){
			return 1;
		}
	}
	return 0;
}
int main(){
	scanf("%s",a+1);
	len=strlen(a+1);
	for(int i=1;i<=len;i++){
		if(a[i]=='?') g[i]=g[i-1]+1;
		else g[i]=g[i-1];
	}
	//将?看成0 
	for(int i=1;i<=len;i++){
		if(a[i]=='1') sum[i]=sum[i-1]+1;
		else sum[i]=sum[i-1];
	}
	int l=1,r=len,ans;
	while(r>=l){
		int mid=(l+r)/2;
		if(judge(mid)){
			l=mid+1;
			ans=mid;
		}
		else{
			r=mid-1;
		}
	}
	cout<<ans<<endl;
}

动态规划

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=1e6+100;
char a[maxn]; 
int dp[maxn][2];
int ans=0;
int main(){
	scanf("%s",a+1);
	int len=strlen(a+1);
	for(int i=1;i<=len;i++){
		if(a[i]=='?'){
			dp[i][0]=dp[i-1][0]+1;
			dp[i][1]=dp[i-1][1]+1;
		}
		else{
			dp[i][a[i]-'0']=dp[i-1][a[i]-'0']+1;
		}
		ans=max(ans,max(dp[i][0],dp[i][1])); 
	}
	cout<<ans<<endl;
	
}
posted @ 2023-11-21 19:15  lipu123  阅读(200)  评论(0)    收藏  举报