题解 P5670【秘籍-反复异或】

$\text{Link}$

这是一篇指令集题解,并非正解。另外,请不要尝试在正式 OI 比赛中使用指令集。

题意

区间加区间后 $m$ 位异或和,$m$ 所有询问相同。

$n,m\le 10^5,0\le a_i< 2^m\le1024$

思路

加/异或,指令集基本操作,这个不用多讲。

虽然已经有了一篇指令集题解,但是我还是来推广一种指令集写法,这种写法的优势在于:

  • 好写好记
  • 可本地运行
  • 运行速度较快(至少在只用 -O2 时比现有的一篇指令集题解 -O2 -Ofast1.3s

这种指令集用 __attribute((vector_size(32))) 实现,可以直接进行一些基本操作,不需要写函数,具体可以直接参考代码。

贴个代码:

#include<bits/stdc++.h>
using namespace std;
typedef unsigned u256 __attribute((vector_size(32)));
#define ll long long
const int N=100000>>3;
int n,m,q;
u256 a[N],ans,tmp;
inline void add(int l,int r,int x){
    u256 xx=u256{x,x,x,x,x,x,x,x};
    if((l>>3)==(r>>3)){
        for(int i=l&7;i<=(r&7);i++){
            a[l>>3][i]+=x;
        }
    }else{
        for(int i=l&7;i<=7;i++){
            a[l>>3][i]+=x;
        }
        for(int i=0;i<=(r&7);i++){
            a[r>>3][i]+=x;
        }
        for(int i=(l>>3)+1;i<=(r>>3)-1;i++){
            a[i]+=xx;
        }
    }
}
inline int query(int l,int r){
    u256 ans=u256{0,0,0,0,0,0,0,0};
    int res=0;
    if((l>>3)==(r>>3)){
        for(int i=l&7;i<=(r&7);i++){
            res^=a[l>>3][i];
        }
    }else{
        for(int i=l&7;i<=7;i++){
            res^=a[l>>3][i];
        }
        for(int i=0;i<=(r&7);i++){
            res^=a[r>>3][i];
        }
        for(int i=(l>>3)+1;i<=(r>>3)-1;i++){
            ans^=a[i];
        }
        for(int i=0;i<=7;i++){
            res^=ans[i];
        }
    }
    return res;
}
int main(){
    n=read(),m=1<<read(),q=read();
    for(int i=0;i<n;i++){
        a[i>>3][i&7]=read();
    }
    while(q--){
        int opt=read(),l=read()-1,r=read()-1;
        if(opt==1){
            add(l,r,read());
        }else{
            write(query(l,r)%m);
            putc('\n');
        }
    }
    flush();
}

谢谢观看,再见 qwq~

posted @ 2021-05-03 21:04  ffffyc  阅读(18)  评论(0)    收藏  举报  来源