题目链接 https://www.51nod.com/Challenge/Problem.html#!#problemId=1391
发散思维(Why and Zjp tql %Zjp and Why)
相信每个人看了这道题都会有思路
:从当前位置向左找最大匹配位置,从当前位置从后找最大匹配位置(原谅我太垃圾只能想出o(n^2)的算法)
我们可以把0当成-1,把1当成1,这样求下前缀和,如果当前位置的前缀和大于0说明1 大于0,反之同理
从前往后找当前位置的前缀小于0的话他的长度就是本身,如果大于0的话,我们需要找当前位置前缀和+ 1的地方是否在原来的时候存在过,如果存在当前位置 - 前缀和+ 1的位置就是最大距离(这是为什么那?)
证明:我们都知道前缀和相同的位置中间的和加起来为0,所以我们就找前缀和+1的位置,你可能会疑惑为什么不找前缀和 + 2 ,+ 3的位置,因为前缀和+ 1位置一定比前缀和 + 2的地方先出现 证毕,倒着找也是同样的道理;
AC代码如下
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//typedef __int128 bll;
typedef long double ld;
const ll maxn = 1e6 + 5;
char a[maxn];
ll b[maxn],c[maxn],flag[maxn];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin >> a + 1;
ll n = strlen(a + 1);
ll cnt = 0;
for(int i = 1; i <= n; i ++)
{
if(a[i] == '0')cnt += -1;
else cnt += 1;
if(cnt < 0) b[i] = i;
else
{
if(flag[cnt + 1] != 0)
{
b[i] = i - flag[cnt + 1];
}
else
{
flag[cnt] = i;
b[i] = 0;
}
}
}
memset(flag,0,sizeof(flag));
cnt = 0;
for(int i = n; i >= 1; i --)
{
if(a[i] == '0')cnt += -1;
else cnt += 1;
if(cnt > 0)c[i] = n - i + 1;
else
{
if(flag[-cnt + 1] != 0)
{
c[i] = flag[-cnt + 1] - i;
}
else
{
flag[-cnt] = i;
c[i] = 0;
}
}
}
ll ma = 0;
for(int i = 1; i < n; i ++)
{
if(b[i] > 0 && c[i + 1] > 0)
ma= max(ma,b[i] + c[i + 1]);
}
cout << ma << endl;
return 0;
}