题目

有一个长为 \(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. 以二进制文件安装K8S之环境准备

    为了k8s集群能正常运行,需要先完成4项准备工作: 1.关闭防火墙 2.禁用SeLinux 3.关闭Swap 4.安装Docker 关闭防火墙 # 查看防火墙状态 getenforce #关闭防火墙, ...

  2. 启动HDFS伪分布式环境时报权限错误

    问题描述 操作系统:Ubuntu18.04 LTS HDFS版本:hadoop-3.2.3 普通用户登录,参照官方文档在单机上安装伪分布式环境时,启动HDFS报权限错误. 具体报错信息如下: $ ./ ...

  3. 记录问题:goland无法识别sdk的问题

    goland版本:2020 go版本:1.20.3最新版 在goland中配置GOROOT时找不到sdk 解决版本: > cd /usr/local/go # 我本地go的安装目录 > c ...

  4. pymysql基本语法,sql注入攻击,python操作pymysql,数据库导入导出及恢复数据---day38

    1.pymysql基本语法 # ### python操作mysql import pymysql ''' # ### 1.基本语法 #(1) 创建连接 host user password datab ...

  5. git开发流程图解,本地分支合并,并推送远程分支步骤

    本地分支合并,并推送远程分支步骤 1.只有当将修改内容commit后 该修改才完全生效,进行merge前需要将两个分支修改的内容都进行commit 2.假设本地两个分支 用于开发的分支:dev 用于同 ...

  6. .NET 链接数据库:证书链是由不受信任的颁发机构颁发的

    错误信息 证书链是由不受信任的颁发机构颁发的 错误环境 .NET web.config链接数据库(发布到服务)时报错 解决方法 下面配置标红部分在你的代码配置中增加或者修改 <add name= ...

  7. 【Azure 应用服务】App Service"访问控制/流量监控"四问

    问题描述 一问:App Service有那些访问限制的方式 二问:访问限制中,是否可以通过域名来进行限制,而不只是IP地址 三问:App Service如何查看到访问者(客户端)的IP地址,访问时间 ...

  8. 代码随想录算法训练营第十三天| 239. 滑动窗口最大值 347.前 K 个高频元素 总结

    239. 滑动窗口最大值 (一刷至少需要理解思路) 卡哥建议:之前讲的都是栈的应用,这次该是队列的应用了.本题算比较有难度的,需要自己去构造单调队列,建议先看视频来理解. 题目链接/文章讲解/视频讲解 ...

  9. Kotlin扩展函数与属性原理解析

    一.扩展函数 扩展函数可以方便地给现有类增加属性和方法而不改动类地代码. 二.原理 fun String.addTo(s: String): String{ return this + s } 反编译 ...

  10. centos7通过配置hosts.allow和hosts.deny限制登陆

    etc/hosts.allow和/etc/hosts.deny两个文件是控制远程访问设置的,通过他可以允许或者拒绝某个ip或者ip段的客户访问linux的某项服务. 我们通常只对管理员开放SSH登录, ...