[cf1083F]The Fair Nut and Amusing Xor
令$c_{i}=a_{i}\oplus b_{i}$,那么也就是要对$c_{i}$执行操作使其变为0
显然有一个贪心的策略,即从左往右,若当前$c_{i}\ne 0$,则执行对$[i,i+k)$异或$c_{i}$的操作,若$i+k\ge n+2$则说明无解
更具体的,定义$p_{i}$为到第$i$个位置上时第$i$个位置上的操作,那么有$p_{i}=p_{i-k}\oplus c_{i-1}\oplus c_{i}$(特别的,$c_{0}=0$,若$i\le 0$则$p_{i}=0$)
解释一下,除去$p_{i-k}$以外,当前所有操作都是$i-1$和$i$一起执行,不难发现这些操作的总影响是$p_{i-k}\oplus c_{i-1}$,初始是$c_{i}$,再异或一下即为当前的值
我们所求的即为$p_{i}$中非0的个数以及判定$p_{i}$($i\ge n-k+2$)是否存在非0数(即无解)
令$c'_{i}=c_{i}\oplus c_{i-1}$,记第$i$组为模$k$余$i$的$j$($1\le j\le n$)的$c'_{j}$所构成的序列($0\le i<k$,不改变相对顺序),每一组显然独立,且对于第$i$组,需要以下两个信息:
1.所有数异或的结果,若存在$i\not\equiv n-k+1(mod\ k)$且结果不为0,则无解
2.前缀异或和中非0数的个数,这个即为答案
对于第一个修改可以很容易支持(维护0的个数),对于第二个直接记录前缀异或和,那么修改即支持后缀异或的操作以及统计非0的个数,也就是全部减去0的个数
再对每一组内部分块,设块大小为$K$,对于每一个块维护桶以及修改懒标记,考虑复杂度:
时间复杂度为$o((\frac{n}{K}+K)q)$,取$K=\sqrt{n}$即为$o(q\sqrt{n})$
空间复杂度为$o(\frac{2^{14}n}{K})$,在最优时间复杂度的取值下可以接受
另外还有一个特殊情况,当$k$较大时每一个块的大小无法达到$K$(如$k=n$时空间会退化为$o(2^{14}n)$),更具体的,当$k>\sqrt{n}$,对每一个块暴力处理,复杂度为$o(\frac{n}{k}q)$,与之前相同
其他情况下,即使每一组恰好多出一个大小为1的块,也就至多多$\sqrt{n}$个块,并没有太大影响
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 200005 4 #define NN 1005 5 int n,k,q,K,x,y,sp,flag,ans_sum,a[N],b[N],cc[N],c[N],len[N],check[N],ans[N]; 6 int bl[N],id[NN][NN],tag[N],tot[NN][(1<<14)]; 7 char s[11]; 8 void add(int k){ 9 if (k!=sp)flag+=(check[k]>0); 10 ans_sum+=ans[k]; 11 } 12 void del(int k){ 13 if (k!=sp)flag-=(check[k]>0); 14 ans_sum-=ans[k]; 15 } 16 void add(int x,int i){ 17 tot[id[x][i/K]][c[i*k+x]]++; 18 if (c[i*k+x]==tag[id[x][i/K]])ans[x]++; 19 } 20 void del(int x,int i){ 21 tot[id[x][i/K]][c[i*k+x]]--; 22 if (c[i*k+x]==tag[id[x][i/K]])ans[x]--; 23 } 24 void update(int x,int y){ 25 del(bl[x]); 26 check[bl[x]]^=y; 27 int i=(x-bl[x])/k; 28 if (k>K){ 29 for(;i<len[bl[x]];i++){ 30 if (!c[i*k+bl[x]])ans[bl[x]]--; 31 c[i*k+bl[x]]^=y; 32 if (!c[i*k+bl[x]])ans[bl[x]]++; 33 } 34 } 35 else{ 36 for(;(i<len[bl[x]])&&(i%K);i++){ 37 del(bl[x],i); 38 c[i*k+bl[x]]^=y; 39 add(bl[x],i); 40 } 41 if (i!=len[bl[x]]){ 42 for(;i<len[bl[x]];i+=K){ 43 ans[bl[x]]-=tot[id[bl[x]][i/K]][tag[id[bl[x]][i/K]]]; 44 tag[id[bl[x]][i/K]]^=y; 45 ans[bl[x]]+=tot[id[bl[x]][i/K]][tag[id[bl[x]][i/K]]]; 46 } 47 } 48 } 49 add(bl[x]); 50 } 51 void write(){ 52 if (flag)printf("-1\n"); 53 else printf("%d\n",n-ans_sum); 54 } 55 int main(){ 56 scanf("%d%d%d",&n,&k,&q); 57 K=(int)sqrt(n); 58 for(int i=0;i<n;i++)scanf("%d",&a[i]); 59 for(int i=0;i<n;i++)scanf("%d",&b[i]); 60 sp=n%k; 61 for(int i=0;i<n;i++){ 62 bl[i]=i%k; 63 len[bl[i]]++; 64 cc[i]=(a[i]^b[i]); 65 } 66 c[0]=cc[0]; 67 for(int i=1;i<n;i++)c[i]=(cc[i-1]^cc[i]); 68 for(int i=k;i<n;i++)c[i]=(c[i]^c[i-k]); 69 for(int i=n-k;i<n;i++)check[bl[i]]=c[i]; 70 if (k>K){ 71 for(int i=0;i<n;i++)ans[bl[i]]+=(c[i]==0); 72 } 73 else{ 74 int V=0; 75 for(int i=0;i<k;i++) 76 for(int j=0;j<len[i];j+=K)id[i][j/K]=++V; 77 for(int i=0;i<n;i++)add(bl[i],(i-bl[i])/k); 78 } 79 for(int i=0;i<k;i++)add(i); 80 write(); 81 for(int i=1;i<=q;i++){ 82 scanf("%s%d%d",s,&x,&y); 83 x--; 84 if (s[0]=='a'){ 85 update(x,(a[x]^y)); 86 if (x<n-1)update(x+1,(a[x]^y)); 87 a[x]=y; 88 } 89 else{ 90 update(x,(b[x]^y)); 91 if (x<n-1)update(x+1,(b[x]^y)); 92 b[x]=y; 93 } 94 write(); 95 } 96 }