题目

有一个长为 \(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. Miniconda安装和使用

    Miniconda概述 Miniconda是什么? 要解释Miniconda是什么,先要弄清楚什么是Anaconda,它们之间的关系是什么? 而要知道Anaconda是什么,最先要明白的是搞清楚什么是 ...

  2. Vulnhub内网渗透DC-6靶场通关

    个人博客 xzajyjs.cn IP DC-6: 192.168.168.4 Kali: 192.168.168.5 信息搜集 arp-scan -l # nmap -sn 192.168.168.0 ...

  3. CentOS6.8下yum安装Nginx

    在/etc/yum.repos.d/目录下创建一个源配置文件nginx.repo: cd /etc/yum.repos.d/ vim nginx.repo 填写如下内容: [nginx] name=n ...

  4. 【Azure Key Vault】使用Azure CLI获取Key Vault 机密遇见问题后使用curl命令来获取机密内容

    问题描述 在使用Azure Key Vault的过程中,遇见无法获取机密信息,在不方便直接写代码的情况下,快速使用Azure CLI指令来验证当前使用的认证是否可以获取到正确的机密值. 使用CLI的指 ...

  5. 【Azure Redis 缓存】Lettuce 连接到Azure Redis服务,出现15分钟Timeout问题

    问题描述 在Java应用中,使用 Lettuce 作为客户端SDK与Azure Redis 服务连接,当遇见连接断开后,长达15分钟才会重连.导致应用在长达15分的时间,持续报错Timeout 问题解 ...

  6. 【Azure 应用服务】App Service for Linux环境中,如何解决字体文件缺失的情况

    问题描述 部署在App Service for Linux环境中的Web App.出现了字体文件缺失的问题,页面显示本来时中文的地方,区别变为方框占位. 问题分析 在应用中,通常涉及到显示问题的有两个 ...

  7. Nebula Graph|如何打造多版本文档中心

    本文首发于 Nebula Graph Community 公众号 世界上没有完美的产品,每个不完美的产品都需要一份文档. 为什么需要文档 打造出一款产品后,我们需要一份文档来回答以下问题: 设计这款产 ...

  8. Codeforces Round 734 (Div. 3)B2. Wonderful Coloring - 2(贪心构造实现)

    思路: 分类讨论: 当一个数字出现的次数大于等于k,那么最多有k个能被染色, 当一个数字出现的次数小于k,南那么这些数字都可能被染色 还有一个条件就是需要满足每个颜色的数字个数一样多,这里记出现次数小 ...

  9. Docker下搭建MySql主从复制

    在Docker环境下搭建MySql主从复制,阅读此文章默认读者具备基础的Docker命令操作. 一.环境 1.Docker版本:Docker version 24.0.5, build ced0996 ...

  10. 真实开发中-redis在项目中的应用场景

    一.需求描述 从自己当前负责参与开发的一个项目中来看,redis主要的应用场景有如下几个,第一个是保存用户信息,这个需要频繁的获取.比如 在打开某一个页面进行查询时,就先需要获取用户信息,看用户是否具 ...