Solution -「NOI2013」向量内积

学不懂线性代数怎么办((

考虑把 \(n\) 个向量归入一个矩阵 \(A\)。根据题意,在模 \(k\) 意义下,\(B = (A \cdot A^T)^2, B_{i, j} = \vec{a}_i\vec{a}_j^T\) 是一个 0/1 矩阵。

不难发现,如果 \(B\) 是一个全 \(1\) 矩阵则说明不存在符合题意的一组向量。否则如果 \(B_{i, j} = 0\)\((i, j)\) 是符合条件的一组解。

\(O(n^2d)\) 这咋判。

考虑随机一个向量的顺序。对于向量 \(\vec{a}_i\) 求其与 \(\vec{a}_j,j < i\) 内积的平方之和,如果所有内积在模 \(k\) 意义下均不等于 \(0\),则该和为 \((i - 1) \bmod k\)

即,如果该和等于 \((i - 1) \bmod k\),则有概率之前没有向量可以与 \(\vec{a_i}\) 配对。否则之前一定存在一个向量可以与 \(\vec{a_i}\) 配对,暴力 Check。

展开吧。

\[\sum _{j = 1} ^{i - 1} (\vec{a}_i\vec{a}_j^T)^2 = \sum _{j = 1} ^{i - 1} \sum _{x = 1} ^{d} \sum _{y = 1} ^{d} a_{i, x} a_{j, x} a_{i, y} a_{j, y} = \sum _{x = 1} ^{d} \sum _{y = 1} ^{d}a_{i, x}a_{i, y} \sum _{j = 1} ^{i - 1} a_{j, x}a_{j, y} \]

#include <cstdio>
#include <algorithm>
using namespace std;

int Abs (int x) { return x < 0 ? -x : x; }
int Max (int x, int y) { return x > y ? x : y; }
int Min (int x, int y) { return x < y ? x : y; }

int Read () {
    int x = 0, k = 1;
    char s = getchar ();
    while (s < '0' || s > '9') {
        if (s == '-')
            k = -1;
        s = getchar ();
    }
    while ('0' <= s && s <= '9') 
        x = (x << 3) + (x << 1) + (s ^ 48), s = getchar ();
    return x * k;
}

void Write (int x) {
    if (x < 0)
        putchar ('-'), x = -x;
    if (x > 9)
        Write (x / 10);
    putchar (x % 10 + '0');
}

void Print (int x, char s) { Write (x), putchar (s); }

const int Maxn = 1e5 + 5;
const int Maxm = 1e2 + 5;

int a[Maxn][Maxm], Sum[Maxn][Maxm], p[Maxn], n, d, k;

int Calc (int x) {
    int Res = 0;
    for (int i = 1; i <= d; i++)
        for (int j = 1; j <= d; j++)
            Res = (Res + a[x][i] * a[x][j] * Sum[i][j]) % k, Sum[i][j] = (Sum[i][j] + a[x][i] * a[x][j]) % k;
    return Res;
}

int Mul (int x, int y) {
    int Res = 0;
    for (int i = 1; i <= d; i++)
        Res = (Res + a[x][i] * a[y][i]) % k;
    return Res;
}

int main () {
    n = Read (), d = Read (), k = Read ();
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= d; j++)
            a[i][j] = Read (), a[i][j] %= k;
    for (int i = 1; i <= n; i++)
        p[i] = i;
    for (int t = 1; t <= 7; t++) {
        random_shuffle (p + 1, p + n + 1);
        for (int i = 1; i <= d; i++)
            for (int j = 1; j <= d; j++)
                Sum[i][j] = 0;
        for (int i = 1; i <= n; i++)
            if (Calc (p[i]) != (i - 1) % k)
                for (int j = 1; j < i; j++)
                    if (!Mul (p[i], p[j])) {
                        Print (Min (p[i], p[j]), ' '), Print (Max (p[i], p[j]), '\n');
                        return 0;
                    }
    }
    Print (-1, ' '), Print (-1, '\n');
    return 0;
}
posted @ 2022-09-17 09:41  STrAduts  阅读(56)  评论(0)    收藏  举报