1 条题解

  • 0
    @ 2025-8-24 22:22:01

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 一扶苏一
    休息结束。邮箱 yifusuyi@qq.com

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

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

    以下是正文


    【倍增,矩阵乘法】【P6569】魔法值

    Analysis

    upd:经评论区老哥提醒,一般情况下乘法对异或没有分配律,不能直接求和变换。内容已修改。

    把题目的式子写的更清晰一点:设 eu,ve_{u, v} 表示 (u,v)(u, v) 之间是否有边,有边为 11,无边为 00,再把题目里的 ff 的两个下角标交换一下,即设 fi,jf_{i, j} 是在第 ii 天,城市 jj 的魔法值,则有:

    $$f_{i, v} = \operatorname{xor}_{u = 1}^n f_{i - 1, u} \times e_{u, v} $$

    现在定义一个 a×ba \times b 矩阵 AA 异或一个 b×cb \times c 矩阵 BB 的结果为一个 a×ca \times c 的矩阵 CC,转移为

    $$C_{i, j} = \operatorname{xor}_{k = 1}^b A_{i, k} \times B_{k, j} $$

    1×n1 \times n 矩阵 FiF_i 的第 11 行第 jj 列表示第 ii 天城市 jj 的魔法值,n×nn \times n 矩阵 EE 的第 ii 行第 jj 列表示 i,ji, j 之间是否有边,可以发现 FiF_i 是由 Fi1F_{i - 1} 异或矩阵 EE 转移而来。

    Fi=Fi1xorEF_i = F_{i - 1} \operatorname{xor} E

    式子看起来长得很像快速幂,快速幂的要求矩阵有结合律,即 $(A \operatorname{xor} B \operatorname{xor} C)_{i, j} = (A \operatorname{xor} (B \operatorname{xor} C))_{i, j}$,来尝试推一下。(下面省略两矩阵间的 xor\operatorname{xor} 运算符)

    AAn×pn \times p 矩阵,BBp×qp \times q 矩阵,CCq×mq \times m 矩阵,则他们的异或和为 n×mn \times m 矩阵。

    $$\begin{aligned}(ABC)_{i, j} = \operatorname{xor}_{x = 1}^q(\operatorname{xor}_{y = 1}^p A_{i, y} \times B_{y, x}) \times C_{x, j} \end{aligned} $$

    需要注意的是,一般情况下,乘法对异或没有分配律。例如对于 3,1,23, 1, 2,$3 \times (1 \operatorname{xor} 2) = 9 \neq (1 \times 3)\operatorname{xor}(2 \times 3) = 5$,因此不能直接去掉上式中的括号。

    但是注意到 C 矩阵一定是一个 0101 矩阵(显然如果进行快速幂,那么一个 0101 矩阵在只做乘法和异或的情况下一定不存在进位,结果还是一个 0101 矩阵)。考虑当 Cx,j=0C_{x, j} = 011 时,将括号去掉把 Cx,jC_{x, j} 乘进去,式子是成立的。证明上可以考虑当 Cx,j=0C_{x, j} = 0 时,括号乘上 Cx,jC_{x, j} 的结果一定是 00,将 Cx,jC_{x, j} 乘进去后,每一项都是 00,异或和还是 00;当 Cx,j=1C_{x, j} = 1 时,括号内每一项的值都没有发生改变。而整个括号的值乘上 11 的值也不会改变,因此二者是相等的。

    由此得到

    $$\begin{aligned}(ABC)_{i, j} = \operatorname{xor}_{x = 1}^q \operatorname{xor}_{y = 1}^p A_{i, y} \times B_{y, x} \times C_{x, j} \end{aligned} $$

    同理,对于 (A(BC))i,j(A(BC))_{i, j},也可以写出式子后用同样的证明去括号,因此二者是相等的。在 CC0101 矩阵时,矩阵异或具有结合律,可以进行快速幂。

    因此有

    Fi=F0xorEiF_{i} = F_0 \operatorname{xor} E^i

    这里 EiE^iEE 自身异或 ii 次。

    那么有一个 naive 的做法是每次询问都进行一次矩阵快速幂,Fai=EaiF_{a_i} = E^{a_i}。时间复杂度为 O(n3qloga)O(n^3q \log a)。期望得分 4040 分。

    注意到对于询问,如果对 EE 进行快速幂的话,由于 EEn×nn \times n 的矩阵,因此做一次的复杂度就为 O(n3)O(n^3)。但是 FF1×n1 \times n 的矩阵,因此 FF 每次异或一个 EE 的幂的复杂度为 O(n2)O(n^2)。考虑不进行快速幂,对 aia_i 进行二进制拆分,拆成 O(loga)O(\log a)22 的幂的形式 ,首先预处理出 E2kE^{2^k} 的值,然后用 FF 依次乘上对应的幂即可。

    预处理的复杂度为 O(n3loga)O(n^3 \log a),单次询问的复杂度为 O(n2loga)O(n^2 \log a)。因此总复杂度 O(n3loga)O(n2qloga)O(n^3 \log a) - O(n^2q \log a)

    另外回复一下评论区疑问,上式复杂度中的 - 不代表减号。对于一个算法,用 ABA-B 表示其预处理部分为 AA 的复杂度,BB 表示其余部分的时间复杂度。

    Code

    namespace Fusu {
    
    const int maxt = 32;
    const int maxn = 105;
    
    int n, q, m;
    ll a[maxn];
    
    struct Mat {
      int x, y;
      ll mt[maxn][maxn];
    
      Mat(const int X = 0, const int Y = 0) : x(X), y(Y) {}
    
      Mat operator*(const Mat &o) const {
        Mat ret(x, o.y);
        for (int i = 1; i <= x; ++i) {
          for (int j = 1; j <= o.y; ++j) {
            ret.mt[i][j] = 0;
            for (int k = 1; k <= y; ++k) {
              ret.mt[i][j] ^= mt[i][k] * o.mt[k][j];
            }
          }
        }
        return ret;
      }
    };
    Mat g[maxt], f;
    
    void Main() {
      qr(n); qr(m); qr(q);
      qra(a + 1, n);
      g[0].x = g[0].y = n;
      for (int u, v; m; --m) {
        qr(u); qr(v);
        g[0].mt[u][v] = g[0].mt[v][u] = 1;
      }
      for (int i = 1, di = i - 1; i < maxt; di = i++) {
        g[i] = g[di] * g[di];
      }
      for (ll x; q; --q) {
        qr(x);
        f.x = 1; f.y = n;
        memcpy(f.mt[1] + 1, a + 1, n * sizeof(ll));
        for (ll w = 1, i = 0; w <= x; w <<= 1, ++i) if (x & w) {
          f = f * g[i];
        }
        qw(f.mt[1][1], '\n');
      }
    }
    
    } // namespace Fusu
    

    看到 U 群老哥用 bitset 乱杀感觉好厉害啊

    • 1

    信息

    ID
    5602
    时间
    1000ms
    内存
    512MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者