zoukankan      html  css  js  c++  java
  • bzoj 5294: [Bjoi2018]二进制

    Description

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

    Solution

    假设知道结论:
    当一个二进制数满足以下任意条件则重排后不能 (mod 3=0)
    1.只出现了一个 (1)
    2.(1) 出现的次数为奇数,且 (0) 出现的为 (0)
    3.(1) 出现的次数为奇数,且 (0) 出现的为 (1)

    证明:
    (1) 容易证明
    (2,3) 的话,我们首先要知道 (2^2 mod 3=1) ,且 (*2^2) 之后依旧满足
    (2^1 mod 3=2),且 (*2^2) 之后依旧满足
    所以有结论:放在偶数位可以贡献 (2),放在奇数位贡献 (1)
    那么如果 (1) 出现了偶数次那么一定可以满足条件,因为把 (1) 都放在后面,恰好可以构成数 (2^k-1),而 (2^k mod 3=1)

    那么如果奇数位上放 (1) 的个数比偶数位多了 (3),那么一定可以拼成满足 (mod 3=0)
    因为奇偶配对之后 (mod 3=0),剩下的奇数位 (3*2 mod 3=0),所以恰好满足

    (1) 出现次数为奇数,且 (0) 出现次数为 (>=3),显然满足
    (1) 出现次数为奇数,且 (0) 出现次数为 (=2),由于总共有奇数位,所以奇数比偶数本身就多 (1) ,也满足
    (0) 出现次数为 (0,1) 时 ,也显然不满足

    综上只需要维护不合法情况:
    1.只出现了一个 (1)
    2.(1) 出现的次数为奇数,且 (0) 出现的为 (0)
    3.(1) 出现的次数为奇数,且 (0) 出现的为 (1)

    (1) 情况和 (2,3) 有交集,我们强制 (1) 条件为 "出现了一个(1),且 (0) 出现了至少 (2) 次"

    线段树分别维护 (dl/dr[2][2]) 表示经过左/右端点,(0) 出现了 (0/1) 次,(1) 出现次数的奇偶性的方案数 (统计情况 (2,3))
    (fl/r[3]) 表示经过左/右端点,(1) 恰好出现了 (1) 次,且 (0) 出现的次数分别为 (0,1,>=2) 的方案数 (统计情况 (1))
    (l/r0) 表示经过左右端点的连续 (0) 的长度
    (c0,c1) (0,1) 的个数

    #include<bits/stdc++.h>
    #define ls (o<<1)
    #define rs (o<<1|1)
    using namespace std;
    template<class T>void gi(T &x){
    	int f;char c;
    	for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
    	for(x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f;
    }
    typedef long long ll;
    const int N=1e5+10;
    int n,a[N],Q,op,x,y;
    struct data{
    	ll s,dl[2][2],dr[2][2],fl[3],fr[3],l0,r0;int c0,c1;
    	inline void init(){
    		for(int i=0;i<2;i++)for(int j=0;j<2;j++)dl[i][j]=dr[i][j]=0;
    		fl[0]=fl[1]=fr[0]=fr[1]=fl[2]=fr[2]=l0=r0=s=c0=c1=0;
    	}
    	data(){init();}
    }tr[N*4];
    inline data merge(data A,data B){
    	data R;
    	for(int i=0;i<2;i++)
    		for(int j=0;j<2;j++){
    			R.dl[i][j]+=A.dl[i][j];R.dr[i][j]+=B.dr[i][j];
    			if(i>=A.c0)R.dl[i][j]+=B.dl[i-A.c0][j^(A.c1&1)];
    			if(i>=B.c0)R.dr[i][j]+=A.dr[i-B.c0][j^(B.c1&1)];
    		}
    	for(int i=0;i<3;i++){
    		R.fl[i]+=A.fl[i];R.fr[i]+=B.fr[i];
    		if(!A.c1)R.fl[min(2,i+A.c0)]+=B.fl[i];
    		if(!B.c1)R.fr[min(2,i+B.c0)]+=A.fr[i];
    	}
    	if(A.c1==1 && B.l0)R.fl[min(2ll,A.c0+B.l0)]++,R.fl[2]+=B.l0-1;
    	if(B.c1==1 && A.r0)R.fr[min(2ll,B.c0+A.r0)]++,R.fr[2]+=A.r0-1;
    	R.l0=(!A.c1?A.c0+B.l0:A.l0);R.r0=(!B.c1?B.c0+A.r0:B.r0);
    	R.c0=A.c0+B.c0;R.c1=A.c1+B.c1;
    
    	R.s+=A.s+B.s;
    	R.s+=A.dr[0][1]*(B.dl[1][0]+B.dl[0][0]);
    	R.s+=A.dr[1][0]*B.dl[0][1];
    	R.s+=A.dr[0][0]*(B.dl[1][1]+B.dl[0][1]);
    	R.s+=A.dr[1][1]*B.dl[0][0];
    	if(B.l0)R.s+=(A.fr[2]+A.fr[1])*B.l0,R.s+=A.fr[0]*(B.l0-1);
    	if(A.r0)R.s+=(B.fl[2]+B.fl[1])*A.r0,R.s+=B.fl[0]*(A.r0-1);
    	
    	return R;
    }
    inline void rep(data &t,int x){
    	t.init();
    	if(x)t.dl[0][1]=t.dr[0][1]=t.c1=t.s=t.fl[0]=t.fr[0]=1;
    	else t.dl[1][0]=t.dr[1][0]=t.c0=t.l0=t.r0=1;
    }
    inline void build(int l,int r,int o){
    	if(l==r){rep(tr[o],a[l]);return ;}
    	int mid=(l+r)>>1;
    	build(l,mid,ls);build(mid+1,r,rs);
    	tr[o]=merge(tr[ls],tr[rs]);
    }
    inline void ins(int l,int r,int o,int sa){
    	if(l==r){rep(tr[o],a[l]);return ;}
    	int mid=(l+r)>>1;
    	if(sa<=mid)ins(l,mid,ls,sa);
    	else ins(mid+1,r,rs,sa);
    	tr[o]=merge(tr[ls],tr[rs]);
    }
    inline data qry(int l,int r,int o,int sa,int se){
    	if(sa<=l && r<=se)return tr[o];
    	int mid=(l+r)>>1;
    	if(se<=mid)return qry(l,mid,ls,sa,se);
    	if(sa>mid)return qry(mid+1,r,rs,sa,se);
    	return merge(qry(l,mid,ls,sa,mid),qry(mid+1,r,rs,mid+1,se));
    }
    int main(){
      freopen("pp.in","r",stdin);
      freopen("pp.out","w",stdout);
      cin>>n;
      for(int i=1;i<=n;i++)gi(a[i]);
      build(1,n,1);
      cin>>Q;
      while(Q--){
    	  gi(op);gi(x);
    	  if(op==1)a[x]^=1,ins(1,n,1,x);
    	  else{
    		  gi(y);
    		  printf("%lld
    ",1ll*(y-x+1)*(y-x+2)/2-qry(1,n,1,x,y).s);
    	  }
      }
      return 0;
    }
    
    
  • 相关阅读:
    OpenGL红宝书例3.1 -- glBufferSubData使用
    JNI调用问题(部分机型崩溃)
    文件编码转换工具
    vs2013安装visual assist和viemu之后提示功能等无效解决
    cocos2d-lua SDK接入
    OpenGL中shader读取实现
    CURL C++网络延时或者最低网速下载设置
    Spring框架
    软件安装方式
    Web前端常见问题
  • 原文地址:https://www.cnblogs.com/Yuzao/p/9069527.html
Copyright © 2011-2022 走看看