------------!
题目背景
在做模拟题的时候,打表出规律,结果找错了(打脸)。
题目描述
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
我所理解的题目
给定一个 01 串,接下来有若干询问与修改。
询问 :给定一个区间【L,R】,你需要回答在这一个区间中有多少个子区间包含不止一个1 或者全为 0。
修改 :将一个数取反。
找到这个规律后,我就----莫队,带修,提分。
然后,我发现我只会带log的带修。。。。。。
于是,我又惊奇的发现,可以在线处理!
答案显然为区间个数减去不合法的区间-------包含且只包含一个 1 的区间个数。
额,公式打不出来。
对于询问
对于每一个 1 :
用 f(i)表示 i 之前有多少个 0 ,用 g(i)表示 i 之后有多少个 0 。
接下来就将答案集中在 1 中了。我们处理出 f(i)* g (i) 的前缀和,存入树状数组,那么就是区间查询了。
再然后,我们特判边界处的 1 。具体如下:
1. 区间中不存在 1,那就不需要处理了。
2. 区间中只有一个 1,那就直接算。
3. 区间中的 1 太多了,我们找出最左边的 1 与最右边的 1 。对它们的贡献做特殊处理。
对于修改:
我们们分两种情况处理:
首先需要找到当前位置的前驱与后继的 1 。(并不包含该点)
1. 0 -> 1 ,更新前驱与后继, 将该位置计入贡献。
2. 1 -> 0 ,更新前驱与后继, 将该位置的贡献删去。
接下来还有一种特殊情况:不存在前驱或后继 !
为了避免大量分类讨论,我们在区间左端与右端加设一个位置,并为该位置上的数标记为 1 ,
在整个询问与回答过程中都将其与其它的数当做一个整体,反正也不会被询问到。
下面是我敲的代码,并不保证正确性!!!额
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 int n,k,m,a[100050]; 5 int opt,x,y,howne[100050]; 6 ll ans,sum,f[100050],g[100050]; 7 ll c[100050],wr; 8 int read() 9 { 10 int w=0; 11 char ch=getchar(); 12 while(ch<'0'||ch>'9') 13 ch=getchar(); 14 while(ch>='0'&&ch<='9') 15 { 16 w=w*10+ch-48; 17 ch=getchar(); 18 } 19 return w; 20 } 21 void calc_pushans(int u,ll v) 22 { 23 while(u<=n) 24 { 25 c[u]+=v; 26 u+=u&-u; 27 } 28 } 29 void calc_pushowne(int u,int v) 30 { 31 while(u<=n) 32 { 33 howne[u]+=v; 34 u+=u&-u; 35 } 36 } 37 ll calc_askans(int u) 38 { 39 if(!u) return 0; 40 ll tmp=0; 41 while(u) 42 { 43 tmp+=c[u]; 44 u-=u&-u; 45 } 46 return tmp; 47 } 48 int calc_askhowne(int u) 49 { 50 if(!u) return 0; 51 int tmp=0; 52 while(u) 53 { 54 tmp+=howne[u]; 55 u-=u&-u; 56 } 57 return tmp; 58 } 59 void Dosomethingfirst() 60 { 61 for(int i=n+1;i>=1;--i) 62 a[i]=a[i-1]; 63 sum=1;n+=2;a[1]=a[n]=1; 64 for(int i=1;i<=n;++i) 65 { 66 if(a[i]) 67 { 68 f[i]=sum; 69 sum=1; 70 } 71 else 72 ++sum; 73 } 74 sum=1; 75 for(int i=n;i>=1;--i) 76 { 77 if(a[i]) 78 { 79 g[i]=sum; 80 calc_pushans(i,g[i]*f[i]); 81 sum=1; 82 } 83 else 84 ++sum; 85 } 86 } 87 int findpre(int l,int r) 88 { 89 if(a[l]) 90 return l; 91 int v=calc_askhowne(l); 92 while(l<r) 93 { 94 int mid=(l+r+1)>>1; 95 if(calc_askhowne(mid)==v) 96 l=mid; 97 else 98 r=mid-1; 99 } 100 return ++l; 101 } 102 int findaft(int l,int r) 103 { 104 int v=calc_askhowne(r); 105 while(l<r) 106 { 107 int mid=(l+r)>>1; 108 if(calc_askhowne(mid)==v) 109 r=mid; 110 else 111 l=mid+1; 112 } 113 return l; 114 } 115 void calc() 116 { 117 Dosomethingfirst(); 118 while(m--) 119 { 120 opt=read(); 121 x=read(); 122 ++x; 123 if(opt==1) 124 { 125 a[x]^=1; 126 int l=findaft(1,x-1); 127 int r=findpre(x+1,n); 128 calc_pushans(l,-f[l]*g[l]); 129 calc_pushans(r,-f[r]*g[r]); 130 if(a[x]==0) 131 { 132 calc_pushowne(x,-1); 133 g[l]=f[r]=r-l; 134 calc_pushans(x,-f[x]*g[x]); 135 f[x]=g[x]=0; 136 } 137 else 138 { 139 calc_pushowne(x,1); 140 f[x]=g[l]=x-l; 141 g[x]=f[r]=r-x; 142 calc_pushans(x,f[x]*g[x]); 143 } 144 calc_pushans(l,f[l]*g[l]); 145 calc_pushans(r,f[r]*g[r]); 146 } 147 else if(opt==2) 148 { 149 y=read();++y; 150 ans=(ll)(y-x+1ll)*(ll)(y-x+2)/2; 151 int l=findpre(x,y); 152 int r=findaft(x,y); 153 if(calc_askhowne(y)==calc_askhowne(x-1)) 154 wr=0; 155 else if(l==r) 156 wr=(ll)(y-l+1ll)*(l-x+1ll); 157 else 158 { 159 wr=calc_askans(y)-calc_askans(x-1); 160 wr-=(f[l]*g[l]+f[r]*g[r]); 161 wr+=((ll)(l-x+1ll)*g[l]+f[r]*(ll)(y-r+1ll)); 162 } 163 printf("%lld\n",ans-wr); 164 } 165 } 166 } 167 int main() 168 { 169 scanf("%d",&n); 170 for(int i=1;i<=n;++i) 171 a[i]=read(); 172 scanf("%d",&m); 173 calc(); 174 return 0; 175 }
151