中國石油大學(華東)暑期集訓--二進制(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。php


Solution:
設cnt0,cnt1分別爲[l,r]區間內的1和0的個數,易得:
  1. if cnt1==1 => 不可整除3
  2. if cnt1&1 and cnt0<2 => 不可整除3

  簡單證實上述結論:node

    顯然結論1是成立的(1<<n不可能整除3),當cnt1爲偶數時,顯然也必定能夠整除3,而當cnt1&1時:ios

    先考慮這種狀況,將一個二進制數將其兩位兩位拆分並求和獲得sum,顯然若是 sum%3==0 ,則該二進制數的十進制必定能夠整除3。ide

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

    那麼,對於奇數個1,從中挑出cnt1-3個「1」兩兩組合,確保對sum%3的結果無貢獻後,再看剩下的3個「1」的狀況:spa

      ①、sum(111)=4 沒法整除。【區間內無0】3d

      ②、sum(1101)=4,sum(1011)=5 沒法整除。【區間內只含有一個0】code

      ③、sum(10101)=3 可整除。【區間內至少含有兩個0】blog

  綜上:內存

    咱們用線段樹去維護上述兩種不合法狀況,再用【總數-不合法數=合法數】來獲得答案。

    其中,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\n",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
相關文章
相關標籤/搜索