1 条题解

  • 0
    @ 2026-2-6 11:19:39

    (由于我比较菜,所以如果有什么锅或者有什么不对的地方欢迎指出)

    应该是打作"归约"而不是"规约",感谢评论区大佬指正。

    如果您有过和lxl谈笑风生的经历,可能会听说过一个叫作归约矩乘的东西,还大概知道它是用来证明一个问题最优时间复杂度不低于某个值的。那么,这个是什么?

    前置知识:

    矩阵乘法

    可能还要一些分块的思想。


    首先先其中一个方向的

    其实归约矩乘,就是对于一个问题,如果我们能够证明它不弱于求 两个mmm*m矩阵相乘这样一个问题,那么解决它的时间复杂度也是不低于解决mmm*m矩阵乘法这样一个问题的。

    nnn*n的矩阵乘法,目前是没O(n2polylog)O(n^2 polylog)polylogpolylog这里表示任意logknlog^knkk是一个常数)做法的。

    然后对于一种特殊的矩阵,0/10/1矩阵(矩阵里的数只有010或1)的乘法,在忽略polygon因子的情况下,最优复杂度和普通的矩阵乘法的时间复杂度是相同的(因为普通矩乘按位拆就是0/1矩阵)。事实上归约矩乘一般都归约成0/10/1矩阵的。

    当然,现在也没有证明矩阵乘法没有n2polylognn^2*polylogn的作法。

    说了半天还是没办法证明时间复杂度下界,那么这玩意有啥用吗?在做题或者出题时还是比较有用的,毕竟对矩阵乘法已经被学术大佬们研究了很多却也没有n2polylogn^2polylog做法,我们在自己做题时也不至于想出矩阵乘法的polylogpolylog做法。就像如果你发现一个题是NPC问题,你总不至于去想多项式时间复杂度的算法吧。

    于是,对于上述问题,我们就不应当去思考有没有m2polylogmm^2polylogm做法。然后事实上,由于那些优于O(n3)O(n^3)的矩乘大多都具有很大的常数,所以在OI上一般找到O(m3)O(m^3)的做法就够了,至于一些时间复杂度更优的做法,就是学术研究的事情了。


    (下面默认n,qn,q同级)

    上面讲的可能有点抽象,那么下面来点例子:

    问题1:

    SP10707 COT2 - Count on a tree II

    题意:给你一棵树,每个节点有一个颜色,若干次询问求树上两个节点路径上的节点的颜色种类数。

    我们假定这个题有一个做法,那么对于两个n/2n/2\sqrt {n/2}*\sqrt{n/2}的0/1矩阵A,B,C=ABC =A*B我们考虑构造下面一种情况:

    一棵树,从root挂下来2n/22*\sqrt {n/2}条链,分为前半部分和后半部分,每部分n/2\sqrt {n/2}条。

    如果Ai,k=1A_{i,k} = 1那么就在前半部分的第ii条链上挂一个颜色为kk的节点,而Bk,j=1B_{k,j}=1在后半部分第jj条链上挂一个颜色为kk的节点。

    rootroot的话就随便搞一个大于n/2\sqrt {n/2}的颜色。

    然后对于Ci,jC_{i,j},它相当于是k=1n[Ai,k=1][Bk,j=1]\sum_{k=1}^n[A_{i,k}=1][B_{k,j}=1],也就是有多少种颜色kk,使得在前半部分的第ii条链中出现且在后半部分的第jj条链中出现,那么就是 :

    前半部分的第ii条链节点数 + 后半部分的第jj条链节点数 + 1 - 两条链链底之间的路径的颜色数。

    那么询问就构造 任意的一个前半部分的链链底 到 任意的一个后半部分的链链底 的颜色数就行了(询问数是O(n)O(n)个)。

    也就是说,假如有一种算法,它可以解决这个问题,那么就可以用它来解决n/2n/2\sqrt {n/2} * \sqrt {n/2}的矩阵乘法问题,因此这个算法的时间复杂度也一定是不低于n/2n/2\sqrt {n/2} * \sqrt {n/2}的矩阵乘法的最优复杂度的。

    问题二:小Z的袜子

    problem

    题意(略有修改):

    一个序列aa,若干次询问l,rl,r求有多少个点对(i,j)(i,j)使得li<jrl \leq i < j\leq rai=aja_i = a_j

    建议读者先自行思考以下如何归约。


    做法(仅简述思路):

    考虑对序列成分成O(n)O(\sqrt n)个块,块分为前半部分的块和后半部分的块。

    0/1矩阵A,B,CA,B,C,C=ABC = A*B

    Ai,k=1A_{i,k} = 1时在前半部分的第ii个块放入数kk

    Bk,j=1B_{k,j} = 1时在后半部分的第jj个块放入数kk

    那么Ci,jC_{i,j}就是前半部分第ii个块对后半部分的第jj个块的贡献。

    定义Q(i,j)Q(i,j)表示询问前半部分第ii个块到后半部分第jj个块的答案。

    那么考虑容斥

    C(i,j)=Q(i,j)Q(i,j1)Q(i+1,j)+Q(i+1,j1)C(i,j) = Q(i,j) - Q(i,j-1) -Q(i+1,j) +Q(i+1,j-1)

    那么即可证明这个问题也是不弱于O(n)O(n)O(\sqrt n)*O(\sqrt n)的矩阵乘法的。

    三、区间逆序对

    problem

    然后你会发现如果把序列反转一下就那么就可以证明区间逆序对不弱于小Z的袜子。

    四、区间加,区间k\le k的数的个数

    现在有修改操作了。

    考虑对于序列分成O(n)O(\sqrt n)块。

    0/1矩阵A,B,C,C=ABA,B,C,C=A*B

    Bk,jB_{k,j}表示在第kk个块放一个数jj

    然后Ai,kA_{i,k}我们考虑用操作维护。

    考虑对于AA按行的操作。

    ii行,如果Ai,k=1A_{i,k}=1那么使第kk个块就的数相比最初的时候+n+n,否则第ii个块的数应当和最初时相同。(可以知道修改操作总共最多O(n)O(n)次)

    完成了一行的操作后,我们就可以放上询问。

    Ci,jC_{i,j}那么就相当于是此时序列里n+jn+j的个数(Ai,k=1A_{i,k}=1要求第kk个块必须处于+n+n状态,Bk,j=1B_{k,j}=1要求第kk个块存在数jj,这样一个块中才有n+jn+j。)

    那么我们就询问全局的n+j\le n+j数个数 减去 全局 n+j1\le n+j-1的数个数就行了。

    询问也可以知道总共最多O(n)O(n)个。

    于是这个问题也是不弱于O(n)O(n)O(\sqrt n)*O(\sqrt n)的矩阵乘法的。


    现在来说说另一个方向的归约

    你们是不是很好奇为什么会有诸如n1.41n^{1.41}这样的奇妙时间复杂度的做法

    其实,这也要用到矩阵乘法,通过一些优于n3n^3的矩阵乘法来优化做法。

    还是来点例子吧

    还是那个题:(时间复杂度分析忽略polylog因子)

    一个序列aa,若干次询问l,rl,r求有多少个点对(i,j)(i,j)使得li<jrl \leq i < j\leq rai=aja_i = a_j

    考虑根号分治,将出现次数排名最多的 SS种数 和其他的数分别考虑。

    其他的数出现次数最多n/Sn/S次,所以我们可以对于这类数,转换成二维数点,时间复杂度O(n2logn/S)O(n^2logn/S)或者实现的精细点可以O(n2S)O(\frac{n^2}{S})

    然后对于排名前SS的数,考虑分块,分成SS块。

    散块部分直接暴力O(n2S)O(\frac{n^2}{S})

    整块部分,我们只要预处理出任意两个块的贡献即可,之后就搞个二维前缀和就行了。

    我们将这SS个数重标号1S1 \sim S

    定义Ai,kA_{i,k}表示第ii个块 新标号中的kk出现次数

    Bk,jB_{k,j}表示第jj个块 新标号中的kk出现次数

    矩阵C=ABC = A*B

    那么Ci,j=i=1SAi,kBk,jC_{i,j} = \sum_{i=1}^SA_{i,k}*B_{k,j},就是块i,ji,j间的贡献。

    假设我们现在矩阵乘法能做到O(nt)O(n^t)

    那么我们这个题的时间复杂度就是O(St+n2S)O(S^t +\frac{n^2}{S}),利用高中数学知识就可以算出最优是O(n2tt+1)O(n^{\frac{2t}{t+1}})

    可以看出,当t<3t < 3的时候就就优于O(nn)O(n\sqrt n)了。

    tt取目前最快的2.372.37,该题的时间复杂度就可以做到传说中的O(n1.41)O(n^{1.41})

    鸣谢:

    lxl等Ynoi群的神仙们给的指点。

    • 1

    Count on a tree II/【模板】树分块

    信息

    ID
    4254
    时间
    2000ms
    内存
    512MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者