Crazy Binary String

本题的核心在于如何表达出所谓“子字符串”中有相同数目的0或1。在这里可以采用前缀和数组来表示这样的情况,即某个区间的区间和是它长度的一半时,这个区间就是所需的区间之一,此时更新答案即可。

当然,也可以使用另一种方案:1和0分别用一组相反数代替,比如1和-1,2和-2,都是可以的。这样就可以表现出当1多的时候,整体区间和为正数,0多的时候,整体区间和为负数。所以当某一区间的区间和再次在某个区间内出现的时候,就可以认为它们之间存在一个合法子字符串。(罗尔定理)也有特殊情况,也就是当区间和恰好为0时,这就代表从这个点到原点都是合法子字符串,需要特判一下。

值得一提的是因为区间和有负数,而记录区间和出现的位置的时候如果使用数组,那么很容易因为负数而造成数组越界,因此用map即可避免这一问题。

#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#define lldin(a) scanf_s("%lld", &a)
#define println(a) printf("%lld\n", a)
#define reset(a, b) memset(a, b, sizeof(a))
const int INF = 0x3f3f3f3f;
using namespace std;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1000000007;
const int tool_const = 19991126;
const int tool_const2 = 2000;
inline ll lldcin()
{
	ll tmp = 0, si = 1;
	char c;
	c = getchar();
	while (c > '9' || c < '0')
	{
		if (c == '-')
			si = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9')
	{
		tmp = tmp * 10 + c - '0';
		c = getchar();
	}
	return si * tmp;
}
///Untersee Boot IXD2(1942)
/**Although there will be many obstructs ahead,
the desire for victory still fills you with determination..**/
/**Last Remote**/
char tmp[500000];
ll sum[500000];
map<ll,ll>loc;
int DETERMINATION()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	ll n;
	cin >> n;
	cin >> (tmp+1);
	ll cnt1 = 0, cnt2 = 0,ans=0;
	for (ll i = 1; i <= n; i++)
	{
		if (tmp[i] == '1')
		{
			sum[i] = sum[i - 1] + 9;//构造区间和
			cnt1++;
		}
		else if(tmp[i]=='0')
		{
			sum[i] = sum[i - 1] - 9;
			cnt2++;
		}
		if (loc[sum[i]] == 0 && sum[i] != 0)//如果这个区间和在前面没出现
			loc[sum[i]] = i;
		else//如果出现过了或者整体区间和为0
			ans = max(ans, i - loc[sum[i]]);
		
	}
	cout << ans << " " << 2 * min(cnt1, cnt2) << endl;
	return 0;
}

当然也可以把这些前缀和记录下来,然后排序之后用二分暴力查找也是可行之策。

#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#define lldin(a) scanf_s("%lld", &a)
#define println(a) printf("%lld\n", a)
#define reset(a, b) memset(a, b, sizeof(a))
const int INF = 0x3f3f3f3f;
using namespace std;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1000000007;
const int tool_const = 19991126;
const int tool_const2 = 2000;
inline ll lldcin()
{
	ll tmp = 0, si = 1;
	char c;
	c = getchar();
	while (c > '9' || c < '0')
	{
		if (c == '-')
			si = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9')
	{
		tmp = tmp * 10 + c - '0';
		c = getchar();
	}
	return si * tmp;
}
///Untersee Boot IXD2(1942)
/**Although there will be many obstructs ahead,
the desire for victory still fills you with determination..**/
/**Last Remote**/
char s[150000];
struct info
{
	ll value, loc;
}infos[150000];
ll sum[150000];
bool cmp(info a, info b)
{
	if (a.value == b.value)
		return a.loc < b.loc;
	else
		return a.value < b.value;
}
ll binary_search(ll query,ll lim)
{
	ll ans = -1;
	ll left = 0,right = lim;
	while (left <= right)
	{
		ll mid = (left + right) >> 1;
		if (infos[mid].value == query)
		{
			ans = mid;
			right = mid - 1;
		}
		else if (infos[mid].value > query)
			right = mid - 1;
		else
			left = mid + 1;
	}
	return ans;
}
int DETERMINATION()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	ll n;
	cin >> n;
	cin >> (s + 1);
	ll cnt1 = 0;
	for (int i = 1; i <= n; i++)
	{
		if (s[i]=='1')
		{
			cnt1++;
			sum[i] = sum[i - 1] + 1;
		}
		else
			sum[i] = sum[i - 1] -1;
		infos[i].loc = i;
		infos[i].value =  sum[i];
	}
	//for (int i = 1; i <= n; i++)
	//	cout << infos[i].value << endl;
	sort(infos, infos + 1 + n, cmp);
	ll ans = 0;
	for (int i = 1; i <= n; i++)
	{
		ll tmp = sum[i];
		ll response = binary_search(tmp,n);
		if (response == -1)
			continue;
		else
			ans = max(ans, i-infos[response].loc);
	}
	cout << ans << " " << 2 * min(cnt1, n - cnt1) << endl;
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值