agc045_b 01 Unbalanced
agc045_b 01 Unbalanced
https://atcoder.jp/contests/agc045/tasks/agc045_b
Tutorial
https://img.atcoder.jp/agc045/editorial.pdf
将0的值看作\(-1\),1的值看作\(1\),设\(sum_i\)表示区间\([1,i]\)的前缀和,则我们要最小化的就是
\[\max_{l,r}\{|sum_r-sum_{l-1}|\} = \max\{sum_i\} - \min \{sum_i\}
\]
设 \(f(M)\) 表示 \(\max\{sum_i\} \le M\) 时, \(\min\{sum_i\}\) 的最大值.
设 \(Z\) 表示 \(\max\{sum_i\}\) 的最小值,则我们要求的就是
\[\min_{M \ge Z}\{M-f(M)\}
\]
考虑如何求出 \(Z\) ,贪心的想,只需要将所有?的位置设为0即可.
考虑如何求出\(f(M)\),考虑以刚才求\(Z\)时的结构为基础从前向后贪心,对于一个?位置,如果将其从0变为1后不会有\(sum_i\)的值超过\(M\)则将其修改为1,这样即可求出\(f(M)\)的值
如此来看,\(f(M)\)和\(f(M+2)\)之间的差最大为 \(2\) .
\[f(M)+2 \ge f(M+2) \\
(M+2)-f(M+2) \ge M-f(M)
\]
所以我们只需要计算 \(Z-f(Z),(Z+1)-f(Z+1)\) 就可以了
Code
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#define debug(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
template<class T> inline bool Cmax(T &x,T y) {return x<y?x=y,1:0;}
const int maxn=1e6+50;
int n;
int sum[maxn],mx[maxn];
bool mark[maxn];
char S[maxn];
int f(int M) {
static int s[maxn]; s[0]=0;
for(int i=1,cnt=0;i<=n;++i) {
if(mark[i]) {
if(mx[i]+2*(cnt+1)<=M) s[i]=1,++cnt;
else s[i]=-1;
}
else s[i]=S[i]=='0'?-1:1;
}
for(int i=1;i<=n;++i) s[i]+=s[i-1];
return *min_element(s,s+n+1);
}
int main() {
scanf("%s",S+1),n=strlen(S+1);
for(int i=1;i<=n;++i) {
if(S[i]=='?') mark[i]=1;
if(S[i]=='1') sum[i]=sum[i-1]+1;
else sum[i]=sum[i-1]-1;
}
for(int i=n;i>=0;--i) {
mx[i]=sum[i];
if(i!=n) Cmax(mx[i],mx[i+1]);
}
int Z=mx[0];
printf("%d\n",min(Z-f(Z),(Z+1)-f(Z+1)));
return 0;
}