题解 - C F 1428 F \mathrm{CF1428F} CF1428F
题目意思
S o l \mathrm{Sol} Sol
考虑对于每个 1 1 1 单独算贡献。
假设 a i = 1 a_i=1 ai=1 那么以其为结尾的连续 1 1 1 的长度为 l l l,那么在 [ 1 , i − l ] [1,i-l] [1,i−l] 的区间找一个最远的 j j j 满足 a j = 1 a_j=1 aj=1 且以其为起头的 连续 1 1 1 段的长度 L ≤ l L\leq l L≤l。这个我们可以用线段树维护区间 max \max max 标记来轻松实现。
假设我们找到了 j j j 考虑如何加入贡献,显然 [ j , i − l ] [j,i-l] [j,i−l] 这段区间的贡献要加 l l l , [ i − l + 1 , i ] [i-l+1,i] [i−l+1,i] 这段区间整体加 1 1 1(每个下标 i i i 作为一个个体)。
这样我们只要维护区间加,区间 max \max max 就可以了。时间复杂度 O ( n log n ) O(n\log n) O(nlogn)
C o d e \mathrm{Code} Code
const int N=5e5+5;
int n,m,tr[N*4],laz[N*4],tr2[N*4],tag[N*4];
int ans,las;
char a[N];
inline void pd(int x,int l,int r,int t1,int t2)
{
if(t1) tag[x]=0,tr[x]=(r-l+1)*t1,tr2[x]=laz[x]=t1;
if(t2) tr[x]+=(r-l+1)*t2,tag[x]+=t2,tr2[x]+=t2;
}
inline void pushdown(int x,int l,int r)
{
if(laz[x]||tag[x])
{
int mid=l+r>>1;
pd(x<<1,l,mid,laz[x],tag[x]);
pd(x<<1|1,mid+1,r,laz[x],tag[x]);
laz[x]=tag[x]=0;
}
}
inline int query(int x,int l,int r,int goal)
{
if(l==r) return l;
int mid=l+r>>1;
pushdown(x,l,r);
if(tr2[x<<1|1]>=goal) return query(x<<1|1,mid+1,r,goal);
else return query(x<<1,l,mid,goal);
}
inline void add(int x,int l,int r,int ll,int rr,int v)
{
if(ll>r||rr<l) return;
if(ll<=l&&r<=rr)
{
tr[x]+=(r-l+1)*v,tag[x]+=v,tr2[x]+=v;
return;
}
int mid=l+r>>1;
pushdown(x,l,r);
add(x<<1,l,mid,ll,rr,v),add(x<<1|1,mid+1,r,ll,rr,v);
tr[x]=tr[x<<1]+tr[x<<1|1];
tr2[x]=max(tr2[x<<1],tr2[x<<1|1]);
}
inline void Add(int x,int l,int r,int ll,int rr,int v)
{
if(ll>r||rr<l) return;
if(ll<=l&&r<=rr)
{
tr[x]=(r-l+1)*v,tr2[x]=v,laz[x]=v;
tag[x]=0;
return;
}
int mid=l+r>>1;
pushdown(x,l,r);
Add(x<<1,l,mid,ll,rr,v),Add(x<<1|1,mid+1,r,ll,rr,v);
tr[x]=tr[x<<1]+tr[x<<1|1];
tr2[x]=max(tr2[x<<1],tr2[x<<1|1]);
}
signed main()
{
scanf("%d",&n);
scanf("%s",a+1);
For(i,1,n)
{
if(a[i]=='1')
{
if(!las) las=i;
int can_reach=query(1,1,n,i-las+1);
add(1,1,n,las,i,1);
if(can_reach<las) Add(1,1,n,can_reach,las-1,i-las+1);
}
else las=0;
ans+=tr[1];
}
io.write(ans),puts("");
return 0;
}