1 条题解

  • 0
    @ 2025-8-24 22:39:51

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Nangu
    加 训

    搬运于2025-08-24 22:39:51,当前版本为作者最后更新于2025-03-14 19:34:46,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    我们考虑对 rr 进行扫描线。

    设当前枚举到右端点 ppaia_i 表示左端点为 ii 时二元组的权值,bib_i 表示数组 aa 的历史和,则对于询问 [l,r][l, r] 答案为 i=lrbi\bigoplus_{i=l}^r b_i

    我们需要做的操作:

    1. 对于 i[l,r]i \in [l, r]ai+1aia_i+1 \to a_i
    2. 对于 i[1,p]i \in [1, p]bixoraibib_i \operatorname{xor} a_i\to b_i
    3. 查询 bb 的区间异或和。

    考虑序列分块。我们先预处理出 fo,xf_{o, x} 表示第 ooi=blbr(ai+x)\bigoplus_{i=bl}^{br} {(a_i+x)} 的值,其中 xBx\le B

    对于第一类操作:

    • 散块:暴力修改,暴力重构。
    • 整块:我们维护一个 tagtag 数组,每次修改整块时 tag[o]++,若 tago=Btag_o=B,须重构整块。

    对于第二类操作:

    • 散块:暴力重构。
    • 整块:直接令 sumboxorfo,tagosumbosumb_o \operatorname{xor} f_{o, tag_o} \to sumb_o,同时维护一个桶 kk,每次将 tagotag_o 加入 kok_o,用于维护 bb

    第三类是平凡的。

    现在我们只剩下了一个问题:如何暴力重构整块?

    我们需要干两件事:重新计算 ff 的值,以及将懒标记下放更新 bb 的值。

    更新 bb 的值相当于对于每一个在桶内的值 xx,执行 bixor(ai+x)bib_i \operatorname{xor} (a_i+x) \to b_i。容易发现这个过程和计算 ff 的过程非常像,因此我们下文只讨论 ff 的处理方法。

    注意到 a+ba+b 可以看作 axorba\operatorname{xor}b 再加上 a+ba+b 所产生的每一个进位。因此,我们可以逐位计算 fxf_x 的进位的个数,则原问题就转化为求对于每一个 22 的正整数幂 kk 以及 xx,计算 xmodk+aimodkkx \bmod k+ a_i \bmod k \ge k 的个数。

    这样直接枚举值域并双指针的做法是 O(Blogn)O(B\log n) 的,考虑进行一点优化。

    我们将 kk 分成 B\le B>B>B 两类。

    对于第一类 kk,令 dpk,ydp_{k, y} 表示 xmodk=yx \bmod k=yxxkk 上的贡献。这个数组的总元素个数是 O(B)O(B) 的。容易线性求出。

    对于第二类 kk,容易发现,此时 xmodk=xx\bmod k=x。发现对于任意的 aia_iaia_i 对一些 xx 造成贡献的一定是 kk 的一段前缀,且这段前缀里 xx 的值域完全相同,于是直接前缀和统计即可。

    如果你看到这里一脸蒙逼,请结合下面的代码一起食用。

    const int B=511;
    void rebuild(const int o){
        const int l=bl[o], r=br[o];
        rep(i, l, r) num[a[i]&B]^=1;//开一个桶
        per(k, 8, 0){
            int s=1<<k+1, now=0;
            rep(i, 1, s-1){
                now^=num[s-i];
                if(now) pre[k][i]=s;//pre[k][i] 表示在 模 2^k 下,i 的贡献
            }
            rep(i, 1, s-1) if(i>>k&1) num[i^1<<k]^=num[i], num[i]=0;
        }
        num[0]=0;
        rep(k, 0, 7){
            const int s=1<<k+1;
            rep(i, 1, s-1){
                pre[k+1][i]^=pre[k][i];
                pre[k+1][i|s]^=pre[k][i];
    			//进行前缀和
                pre[k][i]=0;
            }
        }
        rep(i, 0, B) f[o][i]=pre[8][i], pre[8][i]=0;//算出第一部分(x<=B)的贡献
        rep(i, l, r){
            int p=__builtin_ctz((a[i]>>9)^O);
            if(p) num[(1<<10)-(a[i]&1023)]^=(1<<10+p)-(1<<10);
    		/* 
    		第二部分。
    		此时 x<=B<=k/2
    		想要让 x+a_i%k>=k,a_i 第10,11,12一直到log2(k)位必须为1
    		这就是为什么“贡献一定是一个k的前缀”
    		p即为 a_i 的最长连续1段的长度
    		*/
        }
        int now=0;
        rep(i, 0, B) now^=num[i], num[i]=0, f[o][i]^=now;
        int s=0;
        rep(i, l, r) s^=a[i];//计算不进位的贡献
        rep(i, 0, B){
            f[o][i]^=s;
            if(r-l+1&1) f[o][i]^=i;
        }
    }
    
    
    
    • 1

    [Ynoi2078] 《How to represent part-whole hierarchies in a neural network》阅读报告(更新中...)

    信息

    ID
    8035
    时间
    7000ms
    内存
    512MiB
    难度
    7
    标签
    递交数
    0
    已通过
    0
    上传者