问题 C: 二进制

时间限制: 1 Sec  内存限制: 128 MB
提交: 8  解决: 2
[提交] [状态] [讨论版] [命题人:]

题目描述

pupil发现对于一个十进制数,无论怎么将其的数字重新排列,均不影响其是不是3的倍数。他想研究对于二进制,是否也有类似的性质。于是他生成了一个长为n的二进制串,希望你对于这个二进制串的一个子区间,能求出其有多少位置不同的连续子串,满足在重新排列后(可包含前导0)是一个3的倍数。两个位置不同的子区间指开始位置不同或结束位置不同。由于他想尝试尽量多的情况,他有时会修改串中的一个位置,并且会进行多次询问。

输入

输入第一行包含一个正整数n,表示二进制数的长度。
之后一行n个空格隔开的整数,保证均是0或1,表示该二进制串。
之后一行一个整数m,表示询问和修改的总次数。
之后m行每行为1 i,表示pupil修改了串的第i个位置(0变成1或1变成0),或2 l r,表示pupil询问的子区间是[l,r]。
串的下标从1开始。

输出

对于每次询问,输出一行一个整数表示对应该询问的结果。

样例输入

4
1 0 1 0
3
2 1 3
1 3
2 3 4

样例输出

2
3

提示

对于第一个询问,区间[2,2]只有数字0,是3的倍数,区间[1,3]可以重排成011(2)=3(10),是3的倍数,其他区间均不能重排成3的倍数。
对于第二个询问,全部三个区间均能重排成3的倍数(注意00也是合法的)。

对于20%的数据,1≤n,m≤100;
对于50%的数据,1≤n,m≤5000;
对于100%的数据,1≤n,m≤100000,l≤r。

Solution:

设cnt0,cnt1分别为[l,r]区间内的1和0的个数,易得:
  1. if cnt1==1 => 不可整除3
  2. if cnt1&1 and cnt0<2 => 不可整除3

  简单证明上述结论:

    显然结论1是成立的(1<<n不可能整除3),当cnt1为偶数时,显然也一定可以整除3,而当cnt1&1时:

    先考虑这种情况,将一个二进制数将其两位两位拆分并求和得到sum,显然如果 sum%3==0 ,则该二进制数的十进制一定可以整除3。

    如:111010001=>(01,11,01,00,01),sum=1+3+1+0+1=6。

    那么,对于奇数个1,从中挑出cnt1-3个“1”两两组合,确保对sum%3的结果无贡献后,再看剩下的3个“1”的情况:

      ①、sum(111)=4 无法整除。【区间内无0】

      ②、sum(1101)=4,sum(1011)=5 无法整除。【区间内只含有一个0】

      ③、sum(10101)=3 可整除。【区间内至少含有两个0】

  综上:

    我们用线段树去维护上述两种不合法情况,再用【总数-不合法数=合法数】来得到答案。

    其中,dl/dr[2][2] 代表经过左右节点后:cnt0=0/1,cnt1&1?1:0。

    fl/fr[3] 代表经过左右节点后:满足(cnt1==1 and cnt0==0/1)的方案数。

    L/R表示经过左右节点后,连续0的长度。

代码:

 #include <iostream>
#include <string>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <deque>
#include <map>
#include <set>
#define range(i,a,b) for(auto i=a;i<=b;++i)
#define LL long long
#define ULL unsigned long long
#define elif else if
#define itrange(i,a,b) for(auto i=a;i!=b;++i)
#define rerange(i,a,b) for(auto i=a;i>=b;--i)
#define fill(arr,tmp) memset(arr,tmp,sizeof(arr))
#define IOS ios::sync_with_stdio(false);cin.tie(0)
using namespace std;
int n,m,op,l,r,A[int(1e5+)];
class SegTree{
private:
struct node{
LL s,dl[][],dr[][],fl[],fr[],L,R;
int cnt0,cnt1;
void reset(){
range(i,,)range(j,,)dl[i][j]=dr[i][j]=;
fl[]=fl[]=fr[]=fr[]=fl[]=fr[]=L=R=s=cnt0=cnt1=;
}
node(){reset();}
}tree[int(1e5+)<<];
node comb(node A,node B){
node tmp;
range(i,,)range(j,,){
tmp.dl[i][j]+=A.dl[i][j];
tmp.dr[i][j]+=B.dr[i][j];
if(i>=A.cnt0)tmp.dl[i][j]+=B.dl[i-A.cnt0][j^(A.cnt1&)];
if(i>=B.cnt0)tmp.dr[i][j]+=A.dr[i-B.cnt0][j^(B.cnt1&)];
}
range(i,,){
tmp.fl[i]+=A.fl[i];
tmp.fr[i]+=B.fr[i];
if(!A.cnt1)tmp.fl[min(,i+A.cnt0)]+=B.fl[i];
if(!B.cnt1)tmp.fr[min(,i+B.cnt0)]+=A.fr[i];
}
if(A.cnt1== and B.L){
++tmp.fl[min(2LL,A.cnt0+B.L)];
tmp.fl[]+=B.L-;
}
if(B.cnt1== and A.R){
++tmp.fr[min(2LL,B.cnt0+A.R)];
tmp.fr[]+=A.R-;
}
tmp.L=(!A.cnt1?A.cnt0+B.L:A.L);tmp.R=(!B.cnt1?B.cnt0+A.R:B.R);
tmp.cnt0=A.cnt0+B.cnt0;tmp.cnt1=A.cnt1+B.cnt1;tmp.s+=A.s+B.s;
tmp.s+=A.dr[][]*(B.dl[][]+B.dl[][])+A.dr[][]*B.dl[][];
tmp.s+=A.dr[][]*(B.dl[][]+B.dl[][])+A.dr[][]*B.dl[][];
if(B.L)tmp.s+=(A.fr[]+A.fr[])*B.L+A.fr[]*(B.L-);
if(A.R)tmp.s+=(B.fl[]+B.fl[])*A.R+B.fl[]*(A.R-);
return tmp;
}
void pushup(node &tmp,int x){
tmp.reset();
if(x)tmp.s=tmp.fl[]=tmp.fr[]=tmp.dl[][]=tmp.dr[][]=tmp.cnt1=;
else tmp.dl[][]=tmp.dr[][]=tmp.L=tmp.R=tmp.cnt0=;
};
public:
void build(int l,int r,int rt=){
if(l==r){
pushup(tree[rt],A[l]);
return;
}
int m=(l+r)>>;
build(l,m,rt<<);
build(m+,r,rt<<|);
tree[rt]=comb(tree[rt<<],tree[rt<<|]);
}
void update(int l,int r,int rt,int L){
if(l==r){
pushup(tree[rt],A[l]);
return;
}
int m=(l+r)>>;
if(L<=m)update(l,m,rt<<,L);
else update(m+,r,rt<<|,L);
tree[rt]=comb(tree[rt<<],tree[rt<<|]);
}
node query(int l,int r,int rt,int L,int R){
if(L<=l and r<=R)return tree[rt];
int m=(l+r)>>;
if(R<=m)return query(l,m,rt<<,L,R);
if(L>m)return query(m+,r,rt<<|,L,R);
return comb(query(l,m,rt<<,L,m),query(m+,r,rt<<|,m+,R));
}
}segTree;
void init(){
scanf("%d",&n);
range(i,,n)scanf("%d",A+i);
segTree.build(,n);
scanf("%d",&m);
}
void solve(){
while(m--){
scanf("%d%d",&op,&l);
if(op&)A[l]^=,segTree.update(,n,,l);
else{
scanf("%d",&r);
printf("%lld\n",1LL*(r-l+)*(r-l+)/-segTree.query(,n,,l,r).s);
}
}
}
int main() {
init();
solve();
return ;
}

中国石油大学(华东)暑期集训--二进制(BZOJ5294)【线段树】的更多相关文章

  1. 【BZOJ5294】[BJOI2018]二进制(线段树)

    [BZOJ5294][BJOI2018]二进制(线段树) 题面 BZOJ 洛谷 题解 二进制串在模\(3\)意义下,每一位代表的余数显然是\(121212\)这样子交替出现的. 其实换种方法看,就是\ ...

  2. 【题解】P4247 [清华集训]序列操作(线段树修改DP)

    [题解]P4247 [清华集训]序列操作(线段树修改DP) 一道神仙数据结构(DP)题. 题目大意 给定你一个序列,会区间加和区间变相反数,要你支持查询一段区间内任意选择\(c\)个数乘起来的和.对1 ...

  3. 2019.02.12 bzoj5294: [Bjoi2018]二进制(线段树)

    传送门 题意简述: 给出一个长度为nnn的二进制串. 你需要支持如下操作: 修改每个位置:1变0,0变1 询问对于一个区间的子二进制串有多少满足重排之后转回十进制值为333的倍数(允许前导000). ...

  4. BZOJ5294 BJOI2018二进制(线段树)

    二进制数能被3整除相当于奇数.偶数位上1的个数模3同余.那么如果有偶数个1,一定存在重排方案使其合法:否则则要求至少有两个0且至少有3个1,这样可以给奇数位单独安排3个1. 考虑线段树维护区间内的一堆 ...

  5. BZOJ5294 [BJOI2018] 二进制 【线段树】

    BJOI的题目感觉有点难写 题目分析: 首先推一波结论.接下来的一切都在模3意义下 现在我们将二进制位重组,不难发现的是2^0≡1,2^1≡2,2^2≡1,2^3≡2....所以我们考虑这样的式子 2 ...

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

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

  7. Multidimensional Queries(二进制枚举+线段树+Educational Codeforces Round 56 (Rated for Div. 2))

    题目链接: https://codeforces.com/contest/1093/problem/G 题目: 题意: 在k维空间中有n个点,每次给你两种操作,一种是将某一个点的坐标改为另一个坐标,一 ...

  8. 洛谷P4428二进制 [BJOI2018] 线段树

    正解:线段树 解题报告: 传送门! 话说开始看到这题的时候我想得hin简单 因为关于%3有个性质就是说一个数的各个位数之和%3=这个数%3嘛,小学基础知识? 我就想着,就直接建一棵树,只是这棵树要用个 ...

  9. HZNU-ACM寒假集训Day5小结 线段树 树状数组

    线段树 什么时候用线段树 1.统计量可合并 2.修改量可合并 3.通过统计量可直接修改统计量 一句话:满足区间加法即可使用线段树维护信息 理解Lazy Tage 蓝色是要把信息及时维护的节点,红色是本 ...

随机推荐

  1. HDU 1070 Milk (模拟)

    题目链接 Problem Description Ignatius drinks milk everyday, now he is in the supermarket and he wants to ...

  2. 2017-3-26 webpack入门(一)

    2017-3-26 webpack入门(一) webpack 前端 打包 最近项目里用到了webpack特意总结一下.来源:http://webpackdoc.com 1 概念 1.1 webpack ...

  3. Java线程总结(二)

    自定义线程的数据可以共享,也可以不共享,这要看具体的实现方式. 1.不共享数据多线程实现方式: public class MyThread extends Thread{ private int co ...

  4. Python3安装Celery模块后执行Celery命令报错

    1 Python3安装Celery模块后执行Celery命令报错 pip3 install celery # 安装正常,但是执行celery 命令的时候提示没有_ssl模块什么的 手动在Python解 ...

  5. 64_g3

    gimp-resynthesizer-2.0-6.20160601git787ee5a.fc2..> 11-Feb-2017 05:36 77650 gimp-save-for-web-0.29 ...

  6. 64_g1

    GAPDoc-1.5.1-12.fc26.noarch.rpm 13-Feb-2017 22:37 1082286 GAPDoc-latex-1.5.1-12.fc26.noarch.rpm 13-F ...

  7. 菜鸟学习nodejs--Socket.IO即时通讯

    https://blog.csdn.net/lovemenghaibin/article/details/51263774

  8. python内建方法

    abs all any apply basestring bin bool buffer bytearray bytes callable chr classmethod cmp coerce com ...

  9. JavaScript实现Fly Bird小游戏

    1.分析页面结构,理清需求和功能 游戏有三个界面,分别是开始界面,游戏界面和游戏结束界面. 1.1 开始界面 start.gif 游戏的大背景 上下移动的游戏标题和翅膀摆动的小鸟 start 按钮,点 ...

  10. tornado 响应头 中断 状态码 工作流程

    set_header    设置响应头 clear_header 清除响应头 add_header   增加响应头 self.flush  self.finish  中断 set_status     ...