XJTUOJ #1149 czq的模k异或

题目描述

给定一个长度为\(n\)初始全为0的数列,下标从1开始。定义操作模k异或v为对所有满足\(i\equiv 0\:(mod\:k)\)的下标\(i\),将\(a_i\)异或上整数\(v\)(即令\(a_i=a_i\bigoplus\:v\) )。

给出\(q\)次操作,每次操作之后输出序列的异或和,并且在操作结束之后输出整个序列。

序列的异或和为\(a_1\bigoplus a_2\bigoplus ...\bigoplus a_n\)

输入格式

第一行两个整数\(n,q\)

接下来q行,每行两个整数\(k_i,v_i\)

输出格式

输出共\(q+1\)行,其中前\(q\)行每行一个整数,为每次操作结束后的序列的异或和。

最后一行为操作结束后的序列。

数据范围

\(1\leq n,q\leq 2*10^5\)

\(0\leq k_i,v_i\leq 10^9\)

思路

可以发现有两个子问题,其中第一个:求每次操作完后数列的异或和,是简单的。

\(x\bigoplus x=0\)可得,只要求出1-n中有多少个数是\(k_i\)的倍数,如果是奇数个,那么答案异或上\(v_i\),如果是偶数个,答案不变。

对于第二个子问题,可以想到,既然操作是位运算,那么应该把每一位拆开来处理,我们把初始数组a拆成31个0/1数组,那我们对0/1数组进行操作,就只需要考虑\(k_i\)
(因为异或\(v_i\)相当于对\(v_i\)每一位对应的0/1数组进行操作)。

考虑维护1个0/1数组,每次操作是对于\(k|i\)\(a[i]\bigoplus =1\),那么可以维护所有的k(相同的合并),对于每个个数为奇数的k扫一遍。可是这样最坏情况下不是\(n^2\)的时间复杂度吗?

其实考虑到相同的k会被合并,最坏情况是\(k=1,2,...n\),执行次数为\(\frac{n}{1}+\frac{n}{2}+...+\frac{n}{n}\)。不会超时。

然后把31个0/1数组的信息合并就是最后的答案数组。

代码

#include<cstdio>
#include<cstdlib>
#define maxn 200010
using namespace std;
int a[maxn],x,y,op[32][maxn];
int main(){
    int i,j,n,m,sum=0,x,y,k,N=0;
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;++i){
        scanf("%d%d",&x,&y);
        if(x>n){
            printf("%d\n",sum);
            continue;
        }
        if(x>N) N=x;
        if((n/x)&1) sum^=y;
        for(j=0;j<31&&(1<<j)<=y;++j){
            if((1<<j)&y) op[j][x]^=1;
        }
        printf("%d\n",sum);
    }
    for(i=0;i<31;i++){
        for(j=1;j<=N;j++){
            if(!op[i][j]) continue;
            for(k=j;k<=n;k+=j)
                a[k]^=(1<<i);
        }
    }
    for(i=1;i<=n;i++)
        printf("%d ",a[i]);
    return 0;
}
posted @ 2020-10-20 21:09  文艺平衡树  阅读(130)  评论(0编辑  收藏  举报