[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}$个块,并没有太大影响

 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 }
View Code

 

posted @ 2021-02-22 09:20  PYWBKTDA  阅读(97)  评论(0编辑  收藏  举报