nomura2020_e Binary Programming
nomura2020_e Binary Programming
https://atcoder.jp/contests/nomura2020/tasks/nomura2020_e
Tutorial
https://img.atcoder.jp/nomura2020/editorial.pdf
反向考虑,初始串为\(T\),每次删除一个字符.
发现所有的0都在1之前删除,考虑如果要删除一个1,那么删除它旁边的1是等价的,如果它旁边有0,那么删除0和它对于后面部分的奇偶性影响相同,而保留1不会更差.
如果只剩下1,那么依次删除即可,考虑0的删除顺序
对于连续的1,若长度为偶数,那么无论开始位置,它对于当前局面的贡献都是一样的,所以可以无视,对于奇数的1,类似的,可以变成只有一个1的情况.
那么一个局面就可以被描述为\(a_0,a_1,\cdots,a_k\),表示开始有\(a_0\)个0,之后一个1,然后\(a_1\)个0,...
考虑每个1贡献的上界,对于第\(i\)个1,\(\sum_{j<i} a_j\)的大约一半(根据奇偶性是个定值),是它一定会有的贡献,\(\sum_{j\ge i}\) 是它可能会有的贡献,考虑这个上界是可以达到的.
可以如此构造,先删去所有\(a_0\)中的0,然后在\(a_1\)中保留一个0,其余删除,...,\(a_k\)中保留一个\(0\),其余删除,然后从后向前删去所有剩余的0.
Code
#include <cassert>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#define debug(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
typedef long long ll;
const int maxn=2e5+50;
int n,k; char T[maxn];
vector<int> a[maxn];
namespace seg {
const int maxnode=maxn<<2;
int sum[maxnode][2];
bool rev[maxnode];
inline void rever(int u) {
rev[u]^=1;
swap(sum[u][0],sum[u][1]);
}
inline void pushdown(int u) {
if(rev[u]) {
rever(u<<1);
rever(u<<1|1);
rev[u]=0;
}
}
inline void pushup(int u) {
sum[u][0]=sum[u<<1][0]+sum[u<<1|1][0];
sum[u][1]=sum[u<<1][1]+sum[u<<1|1][1];
}
void build(int u,int l,int r) {
if(l==r) {
sum[u][l&1]=T[l]-'0';
return;
}
int mid=(l+r)>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
void update(int u,int l,int r,int qp) {
if(l==r) {
sum[u][0]=sum[u][1]=0;
return;
}
pushdown(u);
int mid=(l+r)>>1;
if(qp<=mid) update(u<<1,l,mid,qp);
else update(u<<1|1,mid+1,r,qp);
pushup(u);
}
void update(int u,int l,int r,int ql,int qr) {
if(l==ql&&r==qr) {
rever(u);
return;
}
pushdown(u);
int mid=(l+r)>>1;
if(qr<=mid) update(u<<1,l,mid,ql,qr);
else if(ql>mid) update(u<<1|1,mid+1,r,ql,qr);
else {
update(u<<1,l,mid,ql,mid);
update(u<<1|1,mid+1,r,mid+1,qr);
}
pushup(u);
}
}
int main() {
scanf("%s",T+1),n=strlen(T+1);
for(int i=1;i<=n;++i) {
if(T[i]=='0') a[k].push_back(i);
else {
if(T[i+1]=='1') {++i; continue;}
++k;
}
}
if(a[k].size()) ++k;
vector<int> ord;
for(int i=0;i<k;++i) {
for(int j=bool(i);j<a[i].size();++j) ord.push_back(a[i][j]);
}
for(int i=k-1;i>0;--i) {
ord.push_back(a[i][0]);
}
for(int i=1;i<=n;++i) if(T[i]=='1') ord.push_back(i);
seg::build(1,1,n);
ll an=0;
for(int i=0;i<ord.size();++i) {
int x=ord[i];
an+=seg::sum[1][1];
seg::update(1,1,n,x);
seg::update(1,1,n,x,n);
}
printf("%lld\n",an);
return 0;
}