zoukankan      html  css  js  c++  java
  • 中国石油大学(华东)暑期集训--二进制(BZOJ5294)【线段树】

    问题 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的长度。

    代码:

      1 #include <iostream>
      2 #include <string>
      3 #include <cstdio>
      4 #include <cmath>
      5 #include <cstring>
      6 #include <algorithm>
      7 #include <vector>
      8 #include <queue>
      9 #include <deque>
     10 #include <map>
     11 #include <set>
     12 #define range(i,a,b) for(auto i=a;i<=b;++i)
     13 #define LL long long
     14 #define ULL unsigned long long
     15 #define elif else if
     16 #define itrange(i,a,b) for(auto i=a;i!=b;++i)
     17 #define rerange(i,a,b) for(auto i=a;i>=b;--i)
     18 #define fill(arr,tmp) memset(arr,tmp,sizeof(arr))
     19 #define IOS ios::sync_with_stdio(false);cin.tie(0)
     20 using namespace std;
     21 int n,m,op,l,r,A[int(1e5+5)];
     22 class SegTree{
     23 private:
     24     struct node{
     25         LL s,dl[2][2],dr[2][2],fl[3],fr[3],L,R;
     26         int cnt0,cnt1;
     27         void reset(){
     28             range(i,0,1)range(j,0,1)dl[i][j]=dr[i][j]=0;
     29             fl[0]=fl[1]=fr[0]=fr[1]=fl[2]=fr[2]=L=R=s=cnt0=cnt1=0;
     30         }
     31         node(){reset();}
     32     }tree[int(1e5+5)<<2];
     33     node comb(node A,node B){
     34         node tmp;
     35         range(i,0,1)range(j,0,1){
     36             tmp.dl[i][j]+=A.dl[i][j];
     37             tmp.dr[i][j]+=B.dr[i][j];
     38             if(i>=A.cnt0)tmp.dl[i][j]+=B.dl[i-A.cnt0][j^(A.cnt1&1)];
     39             if(i>=B.cnt0)tmp.dr[i][j]+=A.dr[i-B.cnt0][j^(B.cnt1&1)];
     40         }
     41         range(i,0,2){
     42             tmp.fl[i]+=A.fl[i];
     43             tmp.fr[i]+=B.fr[i];
     44             if(!A.cnt1)tmp.fl[min(2,i+A.cnt0)]+=B.fl[i];
     45             if(!B.cnt1)tmp.fr[min(2,i+B.cnt0)]+=A.fr[i];
     46         }
     47         if(A.cnt1==1 and B.L){
     48             ++tmp.fl[min(2LL,A.cnt0+B.L)];
     49             tmp.fl[2]+=B.L-1;
     50         }
     51         if(B.cnt1==1 and A.R){
     52             ++tmp.fr[min(2LL,B.cnt0+A.R)];
     53             tmp.fr[2]+=A.R-1;
     54         }
     55         tmp.L=(!A.cnt1?A.cnt0+B.L:A.L);tmp.R=(!B.cnt1?B.cnt0+A.R:B.R);
     56         tmp.cnt0=A.cnt0+B.cnt0;tmp.cnt1=A.cnt1+B.cnt1;tmp.s+=A.s+B.s;
     57         tmp.s+=A.dr[0][1]*(B.dl[1][0]+B.dl[0][0])+A.dr[1][0]*B.dl[0][1];
     58         tmp.s+=A.dr[0][0]*(B.dl[1][1]+B.dl[0][1])+A.dr[1][1]*B.dl[0][0];
     59         if(B.L)tmp.s+=(A.fr[1]+A.fr[2])*B.L+A.fr[0]*(B.L-1);
     60         if(A.R)tmp.s+=(B.fl[1]+B.fl[2])*A.R+B.fl[0]*(A.R-1);
     61         return tmp;
     62     }
     63     void pushup(node &tmp,int x){
     64         tmp.reset();
     65         if(x)tmp.s=tmp.fl[0]=tmp.fr[0]=tmp.dl[0][1]=tmp.dr[0][1]=tmp.cnt1=1;
     66         else tmp.dl[1][0]=tmp.dr[1][0]=tmp.L=tmp.R=tmp.cnt0=1;
     67     };
     68 public:
     69     void build(int l,int r,int rt=1){
     70         if(l==r){
     71             pushup(tree[rt],A[l]);
     72             return;
     73         }
     74         int m=(l+r)>>1;
     75         build(l,m,rt<<1);
     76         build(m+1,r,rt<<1|1);
     77         tree[rt]=comb(tree[rt<<1],tree[rt<<1|1]);
     78     }
     79     void update(int l,int r,int rt,int L){
     80         if(l==r){
     81             pushup(tree[rt],A[l]);
     82             return;
     83         }
     84         int m=(l+r)>>1;
     85         if(L<=m)update(l,m,rt<<1,L);
     86         else update(m+1,r,rt<<1|1,L);
     87         tree[rt]=comb(tree[rt<<1],tree[rt<<1|1]);
     88     }
     89     node query(int l,int r,int rt,int L,int R){
     90         if(L<=l and r<=R)return tree[rt];
     91         int m=(l+r)>>1;
     92         if(R<=m)return query(l,m,rt<<1,L,R);
     93         if(L>m)return query(m+1,r,rt<<1|1,L,R);
     94         return comb(query(l,m,rt<<1,L,m),query(m+1,r,rt<<1|1,m+1,R));
     95     }
     96 }segTree;
     97 void init(){
     98     scanf("%d",&n);
     99     range(i,1,n)scanf("%d",A+i);
    100     segTree.build(1,n);
    101     scanf("%d",&m);
    102 }
    103 void solve(){
    104     while(m--){
    105         scanf("%d%d",&op,&l);
    106         if(op&1)A[l]^=1,segTree.update(1,n,1,l);
    107         else{
    108             scanf("%d",&r);
    109             printf("%lld
    ",1LL*(r-l+1)*(r-l+2)/2-segTree.query(1,n,1,l,r).s);
    110         }
    111     }
    112 }
    113 int main() {
    114     init();
    115     solve();
    116     return 0;
    117 }
    View Code
  • 相关阅读:
    MS CRM 2011的自定义和开发(10)——CRM web服务介绍(第一部分)——IDiscoveryService
    MS CRM 2011的自定义和开发(7)——视图编辑器(第二部分)
    MS CRM 2011 SDK 5.06版本已经发布
    MS CRM 2011的自定义和开发(11)——插件(plugin)开发(一)
    近来遇到的MS CRM 2011方面的几个问题
    MS CRM 2011的自定义与开发(6)——表单编辑器(第二部分)
    Microsoft Dynamics CRM 2011中,Lookup字段的赋值
    MS CRM 2011的自定义和开发(6)——表单编辑器(第三部分)
    Visual Studio 目标框架造成 命名空间“Microsoft”中不存在类型或命名空间名称“Crm”。是否缺少程序集引用中错误的处理
    一步步学习Reporting Services(二) 在报表中使用简单的参数作为查询条件
  • 原文地址:https://www.cnblogs.com/Rhythm-/p/9455281.html
Copyright © 2011-2022 走看看