P1224 [NOI2013] 向量内积 解题报告


P1224 [NOI2013] 向量内积 解题报告

题意分析

这道题要求我们在 \(n\)\(d\) 维向量中,找出两个不同的向量 \(x_p\)\(x_q\),使得它们的内积是 \(k\) 的倍数。用数学语言来说,就是找到 \(p < q\),满足 \((x_p, x_q) \pmod k = 0\)

一个最直接的想法是暴力枚举所有可能的向量对 \((x_p, x_q)\),计算它们的内积,然后判断是否是 \(k\) 的倍数。这种方法的时间复杂度是 \(O(n^2 d)\)。考虑到 \(n\) 的最大值可以达到 \(10^5\)\(n^2\) 已经是一个非常大的数字了,所以暴力解法肯定会超时,我们需要更高效的算法。

题解的思路非常巧妙,它利用了线性代数和随机化的思想,并根据 \(k\) 的取值(\(k=2\)\(k=3\))采用了不同的策略。

核心思路:将问题转化为矩阵运算

我们可以将这 \(n\)\(d\) 维向量看作一个 \(n \times d\) 的矩阵 \(A\),其中第 \(i\) 行就是向量 \(x_i\)

\[A = \begin{pmatrix} x_{1,1} & x_{1,2} & \cdots & x_{1,d} \\ x_{2,1} & x_{2,2} & \cdots & x_{2,d} \\ \vdots & \vdots & \ddots & \vdots \\ x_{n,1} & x_{n,2} & \cdots & x_{n,d} \end{pmatrix} \]

现在,让我们考虑矩阵 \(A\) 和它的转置矩阵 \(A^T\)(一个 \(d \times n\) 的矩阵)相乘的结果。令 \(B = A \times A^T\)\(B\) 是一个 \(n \times n\) 的矩阵。

\(B\) 矩阵中第 \(i\) 行第 \(j\) 列的元素 \(B_{ij}\) 是如何计算的呢?根据矩阵乘法法则,它等于 \(A\) 的第 \(i\) 行与 \(A^T\) 的第 \(j\) 列的点积。而 \(A^T\) 的第 \(j\) 列恰好就是 \(A\) 的第 \(j\) 行(也就是向量 \(x_j\))。

所以,我们得到了一个惊人的结论:\(B_{ij} = (x_i, x_j)\)

这样一来,原问题“是否存在 \((x_p, x_q)\) 的内积是 \(k\) 的倍数”就等价于“在模 \(k\) 意义下,矩阵 \(B\) 是否存在一个非对角线元素 \(B_{pq}\) (其中 \(p \neq q\)) 为 0”。

直接计算 \(n \times n\) 的矩阵 \(B\) 仍然需要 \(O(n^2 d)\) 的时间,我们还是没有取得进展。但这个转化是后续所有优化的基础。接下来的关键是,我们并不需要计算出整个矩阵 \(B\),而是只需要检验它是否具有我们想要的性质。这里,随机化算法就派上了用场。

Case 1: 当 \(k=2\)

\(k=2\) 时,所有计算都在模 2 意义下进行。

1. “无解”的情况长什么样?

如果没有解,意味着对于所有 \(p \neq q\),都有 \((x_p, x_q) \not\equiv 0 \pmod 2\)。在模 2 的世界里,不等于 0 就意味着等于 1。所以,如果无解,矩阵 \(B\) 在模 2 意义下,所有非对角线元素都应该是 1。

2. 随机化检验

我们如何快速检查 \(B\) 是否具有“所有非对角线元素都为1”这个性质呢?

我们可以随机生成一个 \(n \times 1\) 的列向量 \(R\)(也叫作 \(n\) 维向量),其中每个元素随机取 0 或 1。然后我们计算 \(C = B \times R\)

想象一下,如果矩阵 \(B\) 的第 \(i\)所有元素都是 1,那么 \(C\) 的第 \(i\) 个元素 \(C_i = \sum_{j=1}^n B_{ij}R_j = \sum_{j=1}^n 1 \cdot R_j\)。这个结果就等于向量 \(R\) 中所有元素的和(记为 \(S\))。

如果对于某个 \(i\)\(C_i\) 的值不等于 \(S\),就说明 \(B\) 的第 \(i\) 行并不全是 1,即一定存在某个 \(j\) 使得 \(B_{ij}=0\)。由于我们只关心 \(p \neq q\) 的情况,只要能找到这样一个 \(i\),我们就很有可能找到了解。

3. 高效计算与定位

  • 计算 \(C = B \times R\): 我们并不需要先算出 \(B\)。利用矩阵乘法的结合律,我们可以这样计算:\(C = (A \times A^T) \times R = A \times (A^T \times R)\)
    • 计算 \(R' = A^T \times R\)\(A^T\)\(d \times n\) 矩阵, \(R\)\(n \times 1\) 向量, 结果 \(R'\)\(d \times 1\) 向量。耗时 \(O(nd)\)
    • 计算 \(C = A \times R'\)\(A\)\(n \times d\) 矩阵, \(R'\)\(d \times 1\) 向量, 结果 \(C\)\(n \times 1\) 向量。耗时 \(O(nd)\)
  • 整个检验过程的复杂度只有 \(O(nd)\),非常高效。

4. 算法流程

  1. 将所有输入向量的元素值对 \(k=2\) 取模。
  2. 进行多次随机检验(例如 10 次,以提高正确率)。
  3. 在每次检验中:
    a. 随机生成一个 \(n\) 维的 0/1 向量 \(R\)
    b. 计算 \(S = \sum_{j=1}^n R_j \pmod 2\)
    c. 通过 \(C = A \times (A^T \times R)\) 计算出结果向量 \(C\)
    d. 检查是否存在某个 \(i\),使得 \(C_i \pmod 2 \neq S \pmod 2\)。(注:代码中的判断条件 R.a[i][1] != sum 是一种等价但更简洁的判断方式,它同样能有效地筛选出“有问题”的行)。
    e. 如果找到了这样的 \(i\),说明第 \(i\) 个向量 \(x_i\) 和其他某个向量的内积为 0。这时我们就可以花 \(O(nd)\) 的时间,暴力计算所有 \((x_i, x_j)\) (其中 \(j \neq i\)),找到那个使内积为 0 的 \(x_j\),输出 \(i, j\) 并结束程序。
  4. 如果多次检验都没有发现异常,我们就认为不存在这样的向量对,输出 -1 -1

Case 2: 当 \(k=3\)

\(k=3\) 时,模 2 下的性质 \(x^2 \equiv x\) 不再成立。但我们有另一个非常有用的性质:在模 3 意义下,任何非零数的平方都等于 1\(1^2=1\), \(2^2=4 \equiv 1 \pmod 3\))。

1. 思路转换

原问题是找 \(B_{pq} \equiv 0 \pmod 3\)
利用新性质,这个问题等价于找 \((B_{pq})^2 \equiv 0 \pmod 3\)
如果无解,则对于所有 \(p \neq q\)\(B_{pq}\) 不为 0,那么 \((B_{pq})^2\) 必然为 1。

这样,我们又回到了一个类似 \(k=2\) 的情况:如果无解,一个新矩阵 \(B'\)(其中 \(B'_{ij} = (B_{ij})^2\))的非对角线元素将全为 1。

2. 随机化检验

我们同样可以随机一个 \(n\) 维向量 \(r\)(元素为0, 1, 2),然后去检验一个等式:
对于所有 \(i\),是否都有 \(\sum_{j=1}^n (B_{ij})^2 r_j \equiv \sum_{j=1}^n r_j \pmod 3\)
如果对于某个 \(i\) 不成立,说明 \(B\) 的第 \(i\) 行和某个 \(j\) 的内积 \(B_{ij}\) 为 0。

3. 高效计算与定位

  • 计算 \(\sum_{j=1}^n (B_{ij})^2 r_j\): 这个式子看起来很复杂,但它恰好是某个复杂矩阵乘积的对角线元素。具体来说,它是矩阵 \(B \times \text{diag}(r) \times B^T\) 的第 \(i\) 个对角线元素。(其中 \(\text{diag}(r)\) 是一个对角矩阵,对角线上是向量 \(r\) 的元素)。
  • 我们可以利用结合律来高效计算它:
    1. \(M = A^T \times \text{diag}(r) \times A\)\(M\) 是一个 \(d \times d\) 的小矩阵。
      • \(\text{diag}(r) \times A\) 的计算很简单,就是把 \(A\) 的第 \(j\) 行整体乘以 \(r_j\)
      • 计算 \(M\) 的总时间是 \(O(nd^2)\)
    2. 我们想求的量是 \(B \text{diag}(r) B^T = (A A^T) \text{diag}(r) (A A^T) = A \times M \times A^T\) 的对角线。
    3. \(A \times M \times A^T\) 的第 \(i\) 个对角线元素是 \(A\) 的第 \(i\)\(\times M \times A^T\) 的第 \(i\) 列(也就是 \(A\) 的第 \(i\) 行的转置)。计算一个这样的元素需要 \(O(d^2)\)
    4. 计算所有 \(n\) 个对角线元素,总时间是 \(O(nd^2)\)
  • 整个检验过程的复杂度为 \(O(nd^2)\)。对于本题数据范围,\(nd^2\) 是可以接受的。

4. 算法流程

\(k=2\) 类似:

  1. 将所有输入向量的元素值对 \(k=3\) 取模。
  2. 多次随机检验。
  3. 每次检验:
    a. 随机生成 \(n\) 维向量 \(r\)
    b. 计算 \(S = \sum r_j \pmod 3\)
    c. 高效计算出所有对角线元素 \(V_i = (\text{第 i 个对角线元素}) \pmod 3\)
    d. 检查是否存在 \(i\) 使得 \(V_i \neq S\)
    e. 若存在,则暴力检查 \(x_i\) 与所有其他向量的内积,找到解并输出。
  4. 若多次检验都未成功,则输出 -1 -1

总结

本题的解法是随机化算法在信息学竞赛中的一个经典应用。通过将问题巧妙地转化为矩阵性质的检验,并利用矩阵乘法的结合律和特定模数下的数学性质,我们将一个看似 \(O(n^2d)\) 的问题,根据 \(k\) 的不同,分别用 \(O(nd)\)\(O(nd^2)\) 的高效随机算法解决。这种“不直接求解,而是高效验证”的思想,在处理大规模数据时非常有用。

posted @ 2025-07-22 15:14  surprise_ying  阅读(22)  评论(0)    收藏  举报