1 条题解

  • 0
    @ 2025-8-24 22:53:52

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar zyc070419
    **

    搬运于2025-08-24 22:53:52,当前版本为作者最后更新于2024-01-11 11:55:12,作者可能在搬运后再次修改,您可在原文处查看最新版

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

    以下是正文


    P10009 [集训队互测 2022] 线段树 题解

    前置知识

    • 分块
    • 组合
    • Kummer 定理
    • 高维前缀和

    题解

    各部分的代码都放到最后了……

    Subtask #1

    O(nq)\mathcal{O}(nq) 模拟即可。

    Subtask #2

    由于 i2,ai=0\forall i\ge 2,a_i=0,所以说经过若干次操作之后得到的新数列 {an}\{a_n'\} 一定满足:ai=0a_i'=0ai=a1a_i'=a_1,所以设 bi=[ai=a1]b_i=[a_i'=a_1]。然后就可以 bitset\texttt{bitset} 优化,复杂度 O(nqw)\mathcal{O}(\dfrac{nq}{w})

    Subtask #3

    bitset\texttt{bitset} 优化即可,复杂度 O(nqw)\mathcal{O}(\dfrac{nq}{w})

    Subtask #4

    DD 性质的本质相当于对整个数列做 kk 次差分。

    引理一:

    对于整个数列做 kk 次差分之后的数列 {an}\{a_n'\} 满足:

    $$a_i=\bigoplus_{j=1}^{i}a_j\left[\binom{k}{i-j}\equiv 1\pmod 2\right] $$

    证明方法与数列的 kk 次加法差分结果证明类似,有两种理解方法:

    第一种较为代数的理解,因为位运算每一位独立,所以可以每一位单独考虑,下文设 ai{0,1}a_i\in \{0,1\}。设幂级数 F(x)=i0aixiF(x)=\sum_{i\ge 0}a_i x^i,而异或相当于不进位加法,所以先当成加法来考虑,则进行一次差分相当于将 F(x)F(x)(1x)(1-x),那么 kk 次差分就有:

    $$\begin{aligned} F_k(x)&=F(x)\times (1-x)^k\\ &=\sum_{i\ge 0}a_x\times x^i\sum_{j\ge 0}(-1)^j\binom{k}{j}x^j &=\sum_{i\ge 0}x^i\sum_{p+q=i}a_p\times (-1)^q\times \binom{k}{q} \end{aligned} $$

    所以 $[x^n]F_k(x)=\sum_{i}a_i\times (-1)^{n-i}\times \binom{k}{n-i}$。那么异或差分的系数就是:

    $$(\sum_{i}a_i\times (-1)^{n-i}\times \binom{k}{n-i})\bmod 2=\bigoplus_i a_i\Bigg[\binom{k}{i-j}\equiv 1\pmod 2\Bigg] $$

    第二种理解方式比较组合:考虑 aia_i 在一次差分之后会向哪里贡献对:aia_i'ai+1a_{i+1}' 分别贡献一次,所以说 aja_jaia_i' 的贡献次数就是:有一个点最开始在 jj,操作 kk 次,每次选择向右走一个单位或者原地不动,kk 次之后到达 ii 的方案数,也就是 (kij)\binom{k}{i-j}。方案数为奇数就让 aia_i' 异或 aja_j,否则不修改。

    又因为当且仅当 aj0a_j\not=0 时才有可能对 aia_i' 的值有影响,所以说可以只枚举 aja_j 不为 00 的位置计算,复杂度 O(c(n+q))\mathcal{O}(c(n+q))

    Subtask #5

    只用知道最后一次操作,所以说可以卷积,可以选择进行 DP。

    首先由上可知,aja_j 能对 aia_i 产生贡献当且仅当 (kij)\binom{k}{i-j} 为奇数,也就是不含 22 的次幂,那么可以考虑 Kummer 定理:(kij)\binom{k}{i-j} 为奇数当且仅当 k and (ij)=(ij)k\ \operatorname{and}\ (i-j)=(i-j),其中 and\operatorname{and} 是按位与运算。那么设 dpi,pdp_{i,p} 表示所有满足 iji-j 在二进制下的最高位不超过第 pp 位并且满足 k and (ij)=(ij)k\ \operatorname{and}\ (i-j)=(i-j)aja_j 的异或和。那么有转移:

    $$\left\{ \begin{matrix} dp_{i,p}&=&dp_{i,p-1} && k_p=0\\\\ dp_{i,p}&=&dp_{i,p-1}\oplus dp_{i-2^p,p-1} && k_p=1 \end{matrix} \right. $$

    kpk_p 表示 kk 在二进制下的第 pp 位。

    复杂度 O(nlogn+q)\mathcal{O}(n\log n+q)

    Subtask #6

    因为多次单点询问,每一次询问的之后差分的次数不一样,并且不好递推,所以自然想到分块。

    为了与我的代码表现一致,下文中记 KK 表示 kk 取反后的结果,这样条件就变成了 K and (ij)=0K\ \operatorname{and}\ (i-j)=0

    规定 lowbit(x),highbit(x)\operatorname{lowbit}(x),\operatorname{highbit}(x) 分别表示 xx 在二进制下的最低位,最高位。

    因为可以发现我们异或的是一段一段区间,异或的每一段的区间长度为 2lowbit(K)2^{\operatorname{lowbit}(K)},任意两个需要异或的区间之间的距离最短是 2logbit(K)+12^{\operatorname{logbit}(K)+1}。所以如果 lowbit(K)\operatorname{lowbit}(K) 很大就好了,所以想到了根号分治,或者说值域分块。先设置一个阈值 BB

    dpi,jdp_{i,j} 表示当 K=jK=jaia_i' 的值,其中 j<2Bj< 2^B。记 suml,r=i=1+1raisum_{l,r}=\bigoplus_{i=1+1}^ra_i。记 $l(x)=2^{\operatorname{lowbit}(x)},h(x)=2^{\operatorname{highbit}(x)}$

    为了让转移式子情况没有那么多,下面规定 i0ai=dpi,j=0\forall i \le 0,a_i=dp_{i,j}=0。然后就有转移:

    $$\left\{ \begin{matrix} dp_{i,j} &=& dp_{i-2j,j}\oplus sum_{i-j,i}&& \operatorname{lowbit}(j)=\operatorname{highbit}(j)\\\\ dp_{i,j} &=& dp_{i,j-h(j)}\oplus dp_{i-h(j),j-h(j)}\oplus dp_{i-2h(j),j}&& otherwise. \end{matrix} \right. $$

    由于 BB 位以下的要求已经处理完了,但是无法保证 BB 位及以上是否满足要求,所以说 aia_i' 最终的答案是:

    下面记 y=(K and (2B1)),x=Kyy=(K\ \operatorname{and}\ (2^B-1)),x=K-y

    $$\bigoplus_{j\ge 0}(dp_{i-j\times 2^B,y}\oplus dp_{i-(j+1)\times 2^B,y})\big[(j\times 2^B)\ \operatorname{and}\ x=0\big] $$

    预处理 DP 复杂度 O(n×2B)\mathcal{O}(n\times 2^B),询问复杂度 O(nq2B)\mathcal{O}(\dfrac{nq}{2^B})。取 B=8B=8 时较为优秀。总复杂度大致可以看作 O(nq)\mathcal{O}(n\sqrt{q})

    Subtask #7, 8

    我不是很清楚 Subtask #7 具体有什么算法,或许有什么必须依赖离线的方法?

    因为上面的算法只能处理全局差分,但现在是区间差分,没法搞,所以可以分块。

    对序列分块,整块打整体差分 tag\text{tag},散块暴力。然后整道题就解决了

    可以发现如果只这样搞得话显然很难维护,因为假设我们给第 ii 个整块 [l,r][l,r] 打了一次 tag\text{tag},那么这次操作带来的影响还跟打 tag\text{tag} 之前 al1a_{l-1} 的真实值有关,所以我们需要把每一次打 tag\text{tag} 之前的 al1a_{l-1} 的真实值也维护。

    所以说可以尝试先把每次修改前 al1a_{l-1} 的值存下来。

    现在先假设我们已经把所有操作前 al1a_{l-1} 的值存了下来,整块 [l,r][l,r] 到现在一共进行了 mm 次操作,第 ii 次操作前 al1a_{l-1} 的真实值是 viv_i。那么现在如何快速下放 tag\text{tag} 进行还原呢?

    由于对于 i[l,r]i\in[l,r],有:

    $$a_{i}'=(\bigoplus_{j=l}^{i}\binom{m}{i-j}a_j)\oplus (\bigoplus_{j=1}^{m}b_{i,j}\times v_j) $$

    其中 bi,jb_{i,j}vjv_jaia_i 的贡献系数,bi,j{0,1}b_{i,j}\in \{0,1\}

    左半部分是可以按照 Subtask #5 的方法 DP 的(这部分的贡献在下文称作 段内贡献),而右半部分(这部分贡献下文称作 特殊贡献)首先要求出系数:

    考虑组合意义(其实代数肯定也能推,但比较麻烦):

    viv_i 在第 ii 个时刻第一次到达 ll 这个位置,然后还剩下 mim-i 个时刻可以移动,并且剩下的 mim-i 个时刻每次可以选择原地不动或者向右一步,贡献系数就是路径方案数,即:

    bi,j=(mjil)mod2b_{i,j}=\binom{m-j}{i-l}\bmod 2

    然后再用一次 Kummer 定理,当且仅当 (mj) and (il)=(il)(m-j)\ \operatorname{and}\ (i-l)=(i-l) 时才有贡献。那么如果 mm 是固定的,就能先设数组 Vi=vmiV_i=v_{m-i},然后对 {V0,,Vm1}\{V_0,\cdots ,V_{m-1}\} 做高维后缀异或和得到 VV',那么 vv 数组对 aia_i 的贡献就是 VilV_{i-l}'。综上即:

    $$a_{i}'=(\bigoplus_{j=l}^{i}\binom{m}{i-j}a_j)\oplus V_{i-l}' $$

    那么如何维护 vv 数组呢?要求出 viv_i 就需要求出 al1a_{l-1} 的值,但又不能把 al1a_{l-1} 所在的成块还原,不然复杂度又变成 O(n2)\mathcal{O}(n^2) 的。所以说要支持动态单点算出 al1a_{l-1},更一般性的说,要快速算出每一段(除了最后一段)末尾一个元素的真实值。

    求解方法跟上面说的一样分成两块:

    假设第 ii 个整块的区间为 [Li,Ri][L_i,R_i]。下文以第 ii 个整块为例说明 aRia_{R_i} 如何求。

    对于段内贡献,可以求出新的数组 Aj=aRij,j[0,RiLi]A_j=a_{R_i-j},j\in [0,R_i-L_i],然后对 AA 作高维前缀和得到 AA' 数组,那么如果整块差分了 tt 次,段内贡献就是 AmA'_m。而整块打 tag\text{tag} 是部分影响块内的值的,也就是说 AA' 数组在整块操作中是不会改变的,如果散块暴力的时候会改变,所以求解是可以接受的。

    对于特殊贡献,因为 mm 会变,所以 VV 在不断的改变,高维后缀和也在不断的改变,那就没法维护了,所以做不了了

    mm 虽然在变,但是 RiLiR_i-L_i 是不会变的,所以说要从这个地方为突破口。

    如果 x and (2t1)=(2t1)x\ \operatorname{and}\ (2^t-1)=(2^t-1),其中 tt 为一个常量,那么说明 x1(mod2t)x\equiv -1 \pmod {2^t}

    这个很重要,把位运算变成了我们熟悉的运算。所以说,如果设 RiLi=2t1R_i-L_i=2^t-1 特殊贡献就相当于:

    $$\bigoplus_{j=1}^{m}v_j\big[m-j\equiv -1 \pmod {2^t} \big]=\bigoplus_{j=1}^{m}v_j\big[j\equiv m+1 \pmod {2^t} \big] $$

    所以记 $val_{j}=\bigoplus_{p=1}^{m}v_p\big[p\equiv j \pmod {2^t} \big]$,然后当操作次数为 mm 次时特殊贡献就是 val(m+1)mod2tval_{(m+1)\bmod 2^{t}}

    综上所述就完成了对于 aRia_{R_i} 的动态求解,设块长 B=2tB=2^t,复杂度为 O(qBlogB+nqB)\mathcal{O}(qB\log B+\dfrac{nq}{B}),当 t=8t=8 时最优。

    代码在这里,代码中的 subtask1,subtask2,subtask3,subtask4 分别对应原题中的 Subtask #1,Subtask #2~3,Subtask #4~6,Subtask #7~8。

    • 1

    信息

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