本题的核心在于如何表达出所谓“子字符串”中有相同数目的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;
}