2020 10.27 牛客普及 T2 交换

该博客介绍了如何使用动态规划解决一种特殊序列操作问题:在一个01序列中,找出最长的全为1的子区间,并考虑了序列可交换的操作。通过维护以每个位置为结尾的最长全1子区间的长度,最终找到最大长度。代码实现中,首先初始化动态规划数组,然后遍历序列更新最长全1子区间的长度,并在序列首为1的情况下,考虑交换操作的影响。输出的答案是经过操作后可能的最大全1子区间长度。
摘要由CSDN通过智能技术生成

2020 10.27 普及 T2 交换

题目

题目描述

给一个长度为 n 的 01 序列 s [ 1 ] , s [ 2 ] , . . . . , s [ n ] , s[1],s[2],....,s[n], s[1],s[2],....,s[n]现在可以至多进行 1 次如下操作:
选择 x < n , 1 ≤ x < n x < n,1≤x<n x<n,1x<n,将 s 序列变成 s [ x + 1 ] , s [ x + 2 ] , . . . . . s [ n ] , s [ 1 ] , s [ 2 ] , . . . . s [ x ] s[x+1],s[x+2],.....s[n],s[1],s[2],....s[x] s[x+1],s[x+2],.....s[n],s[1],s[2],....s[x]

输出最长的全为 1 的子区间长度。

输入描述:

一个 01 字符串,表示序列 s s s。( 1 < = ∣ s ∣ < = 100000 1<= |s| <= 100000 1<=s<=100000)

输出描述:

输出一个整数表示答案。

示例1

输入

1001

输出

2

示例2

输入

11111

输出

5

示例3

输入

10111010

输出

3

分析:用数组 f f f记录1的个数。具体操作:设 f [ i ] f[i] f[i]表示以第i个数为结尾的全是1 的最长区间的长度

显然有

f [ i ] { s [ i ] = 0 f [ i ] = 0 s [ i ] = 1 f [ i ] = f [ i − 1 ] + 1 f[i]\begin{cases} s[i]=0& \text{$f[i]=0$}\\ s[i]=1& \text{$f[i]=f[i-1]+1$} \end{cases} f[i]{s[i]=0s[i]=1f[i]=0f[i]=f[i1]+1
然后找到 m a x ( f [ i ] ) max(f[i]) max(f[i]) 记为 m a x n maxn maxn

接着分析交换后的长度:设为 a n s , a n s = 0 ans,ans=0 ans,ans=0
设有变量 t l , 有 f [ t l − 1 ] = t l − 1 tl,有f[tl-1]=tl-1 tl,f[tl1]=tl1
显然,有

a n s { f [ 1 ] = 0 a n s = m a x n ; f [ 1 ] = 1 a n s = m i n ( m a x ( f [ l e n ] + f [ t l − 1 ] , m a x n ) , l e n ) ans\begin{cases} f[1]=0& \text{$ans=maxn;$}\\ f[1]=1& \text{$ans=min(max(f[len]+f[tl-1],maxn),len)$} \end{cases} ans{f[1]=0f[1]=1ans=maxn;ans=min(max(f[len]+f[tl1],maxn),len)
a n s ans ans即为答案

c o d e : code: code:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
//#define r register
#define rep(i,x,y) for(int i=x;i<=y;++i)
#define per(i,x,y) for(int i=x;i>=y;--i)
using namespace std;
typedef long long ll;
string s;
int a[101010],len,f[100010],ans=-222;
int main()
{
	cin>>s;
	len=s.length();
	rep(i,0,len-1)
	 a[i+1]=s[i]-'0';
	rep(i,1,len)
	{
		if(a[i]==1)
		{
			f[i]++;
			int tl=i+1;
			while(tl<=len&&a[tl]==1)
			 f[tl]=f[tl-1]+1,++tl;
			i=tl;
		}
	}
	rep(i,1,len)
	 if(ans<f[i]) ans=f[i];
	if(f[1]>0)
	{
		int tl=2;
		while(tl<=len&&f[tl]>0) ++tl;  //求tl
		ans=max(f[len]+f[tl-1],ans);
        ans=min(ans,len);
	}
	cout<<ans;
	return 0;
}

T h a t ′ s That's Thats o k ok ok

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值