2019牛客暑期多校训练营(第三场)----B-Crazy Binary String

首先发出题目链接:
链接:https://ac.nowcoder.com/acm/contest/883/B
来源:牛客网
涉及:思维,前缀和

点击这里回到2019牛客暑期多校训练营解题—目录贴


题目如下
在这里插入图片描述
在这里插入图片描述
一道比较简单 的思维题

此题让我们找到原字符串中‘0’和‘1’数量相同的子串和子序列。

注意子串在原字符串是连续的;而子序列在原字符串是可以不连续的,但是顺序不能改变


先讨论最长的‘0’‘1’数量相同的子序列:
这个很简单,数一数原字符串‘0’和‘1’的数量,假设‘0’的数量为 s u m 0 sum0 sum0,‘1’的数量为 s u m 1 sum1 sum1

那么满足条件的子序列最长的长度为
2 ∗ m i n ( s u m 0 , s u m 1 ) 2*min(sum0,sum1) 2min(sum0,sum1)


再讨论最长的‘0’‘1’数量相同的子串:
此时有一种方法:将原字符串的‘0’改为‘-1’,然后求原字符串的前缀和。
在这里插入图片描述
由于一个‘1’会和另外一个‘-1’抵消为0,故前缀和中如果存在两个相同的数,说明就存在一个‘0’‘1’相同的子串:
在这里插入图片描述
解释:
0与0之间最长隔了2个单位(红色)
-1与-1之间最长隔了4个单位(绿色)
-2与-2之间最长隔了4个单位(蓝色)
所以最长满足条件子串为 m a x ( 2 , 4 , 4 ) = 4 max(2,4,4)=4 max(2,4,4)=4

通过上面的方法,可以给前缀和每一个数标上它的位置,然后以主键为前缀和数值,次主键为每个数的位置进行从小到大排序,求得每两个相同的数最长隔的单位长度,其中距离最大的单位长度就是答案。具体可以看代码


例子上面举了


代码如下:

#include <iostream>
#include <algorithm>
using namespace std;

int n, word;//n为题目所给变量,word循环存字符串每一个值
struct Num {//前缀和结构体
	int sum;//前缀和的值
	int place;//这个值的位置
};
Num num[100005];//前缀和结构体数组
int sum1 = 0, sum0 = 0;//sum1为'1'的数量,sum0为'0'的数量
int ans1, ans2 = 0;//ans1为最长子序列长度的一半,ans2位最长子串长度

bool comp(Num a, Num b) {//以sum为主键,place为次主键
	if(a.sum == b.sum)	return a.place < b.place;
	else return a.sum < b.sum;
}

int main() {
	scanf("%d", &n);
	num[0].sum = num[0].place = 0;//先将num[0]和num[n+1]初始化
	num[n+1].sum = 100001;
	for(int i = 1; i <= n; i++) {
		scanf("%1d", &word);//循环输入每一个字符
		if(word == 1) {
			num[i].sum = (i - 1 == 0? 0: num[i-1].sum) + 1;//更新前缀和数组
			sum1++;//记录字符'1'个数
		}
		else{
			num[i].sum = (i - 1 == 0? 0: num[i-1].sum) - 1;//更新前缀和数组
			sum0++;//记录字符'0'个数
		}
		num[i].place = i;//记录每个值的位置
	}
	ans1 = min(sum1, sum0);//最长子序列长度的一半
	sort(num, num + n + 1, comp); //按照上述方法排序
	int flag = 0; //记录每一串前缀和数相同的第一个数的位置
	for(int i = 1; i <= n; i++) {
		if(num[i].sum != num[i-1].sum) {//记录相同数开始位置
			flag = i;
		}
		else if(num[i].sum != num[i+1].sum) {//遍历到相同数最后一个位置
			ans2 = max(ans2, num[i].place - num[flag].place);//更新答案
		}
	}
	printf("%d %d", ans2, ans1*2);
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值