题目

有一个长为 \(n\) 的二进制串,支持单个位置取反,对于这个二进制串的一个子区间,

求出其有多少位置不同的连续子串,满足在重新排列后(可包含前导0)是一个 3 的倍数。


分析

考虑对于单个位置\(2^i\bmod 3\)为\(1,2,1,2,\cdots\)

3的倍数有很多种情况,考虑补集转化,

设0的个数为\(c0\),1的个数为\(c1\),则不是3的倍数当且仅当

\[\begin{cases}c1=1\&c0>1\\c1 \bmod 2==1\&c0\leq 1\end{cases}
\]

由于支持单点修改,所以还需要一个线段树,

一个区间的答案等于左右区间的答案加上合并后多出的答案

一条一条考虑,上面这个只考虑\(c1=1\),再减掉\(c0\leq 1\)的情况

单考虑\(c1=1\),即需要维护前后缀0的最长长度\(l0,r0\),

为了少判断,还需要维护\(l1,r1\)表示只有1个1的前后缀个数

那合并后多出的答案就是\(lson.r1*rson.l0+lson.r0+rson.l1\)

然后对于\(c0=1\)的情况当且仅当一个0和一个1相邻,那么合并的时候直接判断即可

对于\(c0=0\)的情况由于下一种情况被放到上面处理所以没有重复

对于\(c1\bmod 2==1\&c0\leq 1\)的情况,

设\(f[0/1][0/1]\)表示前缀或后缀0的个数为0或1且1的个数为偶数或奇数,直接转移即可


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#define rr register
using namespace std;
const int N=100011; typedef long long lll; int n,a[N];
struct rec{int lo,ro,co,cz,lz,rz,f[2][2],g[2][2]; lll w;}b[N<<2];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(lll ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline rec pup(rec t0,rec t1){
rr rec t;
t.lz=t0.lz+(t0.co?0:t1.lz),t.rz=t1.rz+(t1.co?0:t0.rz);
t.co=t0.co+t1.co,t.cz=t0.cz+t1.cz;
t.lo=t0.lo+(t0.co?(t0.co==1?t1.lz:0):t1.lo);
t.ro=t1.ro+(t1.co?(t1.co==1?t0.rz:0):t0.ro);
for (rr int i=0;i<2;++i)
for (rr int j=0;j<2;++j){
t.f[i][j]=t0.f[i][j]+(i>=t0.cz?t1.f[i-t0.cz][(j^t0.co)&1]:0);
t.g[i][j]=t1.g[i][j]+(i>=t1.cz?t0.g[i-t1.cz][(j^t1.co)&1]:0);
}
t.w=t0.w+t1.w+1ll*t0.rz*t1.lo+1ll*t0.ro*t1.lz;
for (rr int i0=0;i0<2;++i0)
for (rr int i1=0;i1<2;++i1) if (i0+i1<2)
t.w+=1ll*t0.g[i0][0]*t1.f[i1][1]+1ll*t0.g[i0][1]*t1.f[i1][0];
if ((!t0.rz&&t1.lz)||(t0.rz&&!t1.lz)) --t.w;
return t;
}
inline void pdown(rec &t,int x){
memset(t.f,0,sizeof(t.f));
memset(t.g,0,sizeof(t.g));
if (x) t.lo=t.ro=t.co=t.w=1,t.cz=t.lz=t.rz=0,t.f[0][1]=t.g[0][1]=1;
else t.lo=t.ro=t.co=t.w=0,t.cz=t.lz=t.rz=1,t.f[1][0]=t.g[1][0]=1;
}
inline void build(int k,int l,int r){
if (l==r){pdown(b[k],a[l]); return;}
rr int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
b[k]=pup(b[k<<1],b[k<<1|1]);
}
inline void update(int k,int l,int r,int x){
if (l==r){pdown(b[k],a[l]); return;}
rr int mid=(l+r)>>1;
if (x<=mid) update(k<<1,l,mid,x);
else update(k<<1|1,mid+1,r,x);
b[k]=pup(b[k<<1],b[k<<1|1]);
}
inline rec query(int k,int l,int r,int x,int y){
if (l==x&&r==y) return b[k];
rr int mid=(l+r)>>1;
if (y<=mid) return query(k<<1,l,mid,x,y);
else if (x>mid) return query(k<<1|1,mid+1,r,x,y);
else return pup(query(k<<1,l,mid,x,mid),query(k<<1|1,mid+1,r,mid+1,y));
}
signed main(){
n=iut();
for (rr int i=1;i<=n;++i) a[i]=iut();
build(1,1,n);
for (rr int T=iut();T;--T){
rr int opt=iut();
if (opt==1){
rr int x=iut();
a[x]^=1,update(1,1,n,x);
}else{
rr int l=iut(),r=iut();
rr rec t=query(1,1,n,l,r);
rr lll ans=1ll*(r-l+1)*(r-l+2)>>1;
print(ans-t.w),putchar(10);
}
}
return 0;
}

#线段树#洛谷 4428 [BJOI2018]二进制的更多相关文章

  1. Bzoj5294/洛谷P4428 [Bjoi2018]二进制(线段树)

    题面 Bzoj 洛谷 题解 考虑一个什么样的区间满足重组之后可以变成\(3\)的倍数.不妨设\(tot\)为一个区间内\(1\)的个数.如果\(tot\)是个偶数,则这个区间一定是\(3\)的倍数,接 ...

  2. 线段树 洛谷P3932 浮游大陆的68号岛

    P3932 浮游大陆的68号岛 题目描述 妖精仓库里生活着黄金妖精们,她们过着快乐,却随时准备着迎接死亡的生活. 换用更高尚的说法,是随时准备着为这个无药可救的世界献身. 然而孩子们的生活却总是无忧无 ...

  3. [线段树]洛谷P5278 算术天才⑨与等差数列

    题目描述 算术天才⑨非常喜欢和等差数列玩耍. 有一天,他给了你一个长度为n的序列,其中第i个数为a[i]. 他想考考你,每次他会给出询问l,r,k,问区间[l,r]内的数从小到大排序后能否形成公差为k ...

  4. 区间连续长度的线段树——洛谷P2894 [USACO08FEB]酒店Hotel

    https://www.luogu.org/problem/P2894 #include<cstdio> #include<iostream> using namespace ...

  5. AC日记——校门外的树 洛谷 P1047

    题目描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,……,L,都种 ...

  6. 带修主席树 洛谷2617 支持单点更新以及区间kth大查询

    题目链接:https://www.luogu.com.cn/problem/P2617 参考博客:https://blog.csdn.net/dreaming__ldx/article/details ...

  7. 洛谷P1582 倒水 二进制 lowbit __builtin_popcount

    P1582 倒水:https://www.luogu.org/problemnew/show/P1582 题意: 给定n瓶装有1升的水瓶,每次可以把两瓶装水量相同的水和成一瓶,问最少还要增加几瓶装有1 ...

  8. 洛谷P1582 倒水 二进制的相关应用

    https://www.luogu.org/problem/P1582 #include<bits/stdc++.h> using namespace std; long long N,K ...

  9. 洛谷P4427 [BJOI2018]求和

    \(\Large\textbf{Description: } \large{一颗n个节点的树,m次询问,每次查询点i到点j的路径上所有节点点深度的k次方的和并对998244353取模(1\leq n, ...

  10. BZOJ5259/洛谷P4747: [Cerc2017]区间

    BZOJ5259/洛谷P4747: [Cerc2017]区间 2019.8.5 [HZOI]NOIP模拟测试13 C.优美序列 思维好题,然而当成NOIP模拟题↑真的好吗... 洛谷和BZOJ都有,就 ...

随机推荐

  1. 什么是数据同步利器DataX,如何使用?

    转载至我的博客 https://www.infrastack.cn ,公众号:架构成长指南 今天给大家分享一个阿里开源的数据同步工具DataX,在Github拥有14.8k的star,非常受欢迎,官网 ...

  2. RK3568开发笔记(二):入手RK3568开发板的套件介绍、底板介绍和外设测试

    前言   本篇主要介绍RK3568芯片和入手开发板的底板介绍以及开发板的外设.   开发板   笔者的开发板是全套+10.1寸屏. 开发板实物     开发板资源    开发版本提供资料     开发 ...

  3. Singularity容器

    """参考文档 https://apptainer.org/user-docs/master/build_a_container.html ""&qu ...

  4. Flutter学习

    常用网址 免费下载 !<AliFlutter 体系化建设和实践> Flutter 开发文档 Flutter实战 Dart 编程语言概览 pub仓库 main函数使用了(=>)符号, ...

  5. React之父组件向子组件传值

    class Parent extends React.Component{ constructor(){ super(); this.state={co:"red"} } rend ...

  6. Apache Hudi 在 vivo 湖仓一体的落地实践

    作者:vivo 互联网大数据团队 - Xu Yu 在增效降本的大背景下,vivo大数据基础团队引入Hudi组件为公司业务部门湖仓加速的场景进行赋能.主要应用在流批同源.实时链路优化及宽表拼接等业务场景 ...

  7. IDEA关联Tomcat(详细教程+安装包)

    IDEA关联Tomcat 下载Tomcat安装包并解压到全英文目录 第一步:打开IDEA--Settings 第二步:搜索application--进入Application Services--点击 ...

  8. 适用于AbpBoilerplate的RocketChat Api库

    RocketChat 适用于AbpBoilerplate的RocketChat Api库 Rocket.Chat 是一个免费.开源.可扩展.高度可定制且安全的平台,可让您与团队进行交流和协作.共享文件 ...

  9. vscode 合并分支 举例 master merge dev

    举例 将 dev 开发线 合并到 master 1 确定你在dev线,将dev代码改动全部提交 2 切换master,确定是最新代码,不确定就pull下,选择合并分支,见上图 3 在下拉的提示框中选择 ...

  10. vscode 格式化 vue 等文件的 配置 eslint vetur prettier Beautify

    需求 自动格式化需求 多行回车 合并一行,去分号 最后一个逗号,自动删除,符合eslint 结果 虽然能用了,但是 百度好几个方案,也不知道哪个对哪个,太忙没时间弄了. 配置文件记录 eslint 得 ...