题解 向量内积
Description
两个 \(d\) 维向量 \(A=[a_1, a_2 ,...,a_d]\) 与 \(B=[b_1 ,b_2 ,...,b_d]\) 的内积为其相对应维度的权值的乘积和,即:
\[(A,B) = \displaystyle \sum_{i=1}^d{a_ib_i} = a_1b_1 + a_2b_2 + \ldots + a_db_d
\]
现有 \(n\) 个 \(d\) 维向量 \(x_1, \ldots, x_n\),小喵喵想知道是否存在两个向量的内积为 \(k\) 的倍数。请帮助她解决这个问题。
第一行包含 \(3\) 个正整数 \(n,d,k\),分别表示向量的个数、维数以及待检测的倍数。
接下来 \(n\) 行每行有 \(d\) 个非负整数,其中第 \(i\) 行的第 \(j\) 个整数表示向量 \([x_i]\) 的第 \(j\) 维权值 \(x_{i,j}\)。
包含两个整数,用空格隔开。
如果存在两个向量 \(x_p,x_q\) 的内积为 \(k\) 的整数倍,则输出两个向量的编号 \(p\) 与 \(q\)(要求 \(p<q\))。如果存在多组这样的向量组合,输出其中任意一组即可。
若不存在这样的向量组合,则输出两个 \(-1\)。
测试点编号 | \(n\) | \(d\) | \(k\) | \(x_i\) |
---|---|---|---|---|
\(1\) | \(2\) | \(20\) | \(2\) | \(\le 10\) |
\(2\) | \(5\) | \(20\) | \(2\) | \(\le 10\) |
\(3\) | \(10\) | \(20\) | \(3\) | \(\le 10\) |
\(4\) | \(20\) | \(20\) | \(2\) | \(\le 100\) |
\(5\) | \(50\) | \(20\) | \(3\) | \(\le 100\) |
\(6\) | \(50\) | \(50\) | \(2\) | \(\le 1000\) |
\(7\) | \(50\) | \(50\) | \(3\) | \(\le 3000000\) |
\(8\) | \(80\) | \(80\) | \(2\) | \(\le 2000000\) |
\(9\) | \(100\) | \(100\) | \(3\) | \(\le 3000000\) |
\(10\) | \(500\) | \(100\) | \(3\) | \(\le 3000000\) |
\(11\) | \(1000\) | \(100\) | \(2\) | \(\le 2000000\) |
\(12\) | \(1000\) | \(100\) | \(3\) | \(\le 3000000\) |
\(13\) | \(10000\) | \(100\) | \(2\) | \(< 10\) |
\(14\) | \(10000\) | \(100\) | \(3\) | \(< 10\) |
\(15\) | \(15000\) | \(100\) | \(2\) | \(< 10\) |
\(16\) | \(18000\) | \(100\) | \(2\) | \(< 10\) |
\(17\) | \(20000\) | \(100\) | \(2\) | \(< 10\) |
\(18\) | \(50000\) | \(30\) | \(3\) | \(< 10\) |
\(19\) | \(80000\) | \(30\) | \(3\) | \(< 10\) |
\(20\) | \(100000\) | \(30\) | \(3\) | \(< 10\) |
Solution
考虑到正经做法不是很好做,考虑不太正经的做法。
首先可以发现 \(k\le 3\),那么先考虑 \(k=2\) 时候的情况。可以发现,如果对于 \(i\) 存在:
\[\sum_{j=1}^{i-1}|x_i·x_j| \not\equiv i-1 \pmod 2
\]
就说明一定存在一个解了。正确概率不是很会算。快速算的话,可以对向量做个前缀和。
考虑 \(k=3\) ,你发现 \(x^{k-1}\equiv \pmod k\) ( \(k\) 为质数),所以如果对于 \(i\) 存在:
\[\sum_{j=1}^{i-1}|x_i·x_j|^2\not\equiv i-1\pmod 2
\]
那么也说明一定存在一个解了。这个也可以用前缀和算,复杂度 \(\Theta(nd^2)\)。
Code
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define MAXN 100005
#define MAXM 105
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
int n,d,mod,s[MAXN][MAXM],ind[MAXN],s1[MAXM],s2[MAXM][MAXM];
signed main(){
// freopen ("P1224_18.in","r",stdin);
srand (20050913);
read (n,d,mod);
for (Int i = 1;i <= n;++ i) for (Int j = 1;j <= d;++ j) read (s[i][j]),s[i][j] %= mod;
for (Int i = 1;i <= n;++ i) ind[i] = i;
for (Int times = 1;times <= 1;++ times){
random_shuffle(ind + 1,ind + n + 1);
if (mod == 2){
memset (s1,0,sizeof (s1));
for (Int i = 1;i <= n;++ i){
int ans = 0;
for (Int j = 1;j <= d;++ j) ans ^= s[ind[i]][j] & s1[j],s1[j] ^= s[ind[i]][j];
if (ans == (i - 1) % mod) continue;
for (Int j = 1;j < i;++ j){
ans = 0;
for (Int k = 1;k <= d;++ k) ans ^= s[ind[i]][k] & s[ind[j]][k];
if (!ans){
write (min (ind[i],ind[j])),putchar (' '),write (max (ind[i],ind[j])),putchar ('\n');
return 0;
}
}
}
}
else{
memset (s2,0,sizeof (s2));
for (Int i = 1;i <= n;++ i){
// cout << i << endl;
int ans = 0;
for (Int k1 = 1;k1 <= d;++ k1)
for (Int k2 = 1;k2 <= d;++ k2)
(ans += s[ind[i]][k1] * s[ind[i]][k2] * s2[k1][k2]),
(s2[k1][k2] += s[ind[i]][k1] * s[ind[i]][k2]);
ans %= mod;
if (ans == (i - 1) % mod) continue;
for (Int j = 1;j < i;++ j){
ans = 0;
for (Int k = 1;k <= d;++ k) (ans += s[ind[i]][k] * s[ind[j]][k] % mod) %= mod;
if (!ans){
write (min (ind[i],ind[j])),putchar (' '),write (max (ind[i],ind[j])),putchar ('\n');
return 0;
}
}
}
}
}
puts ("-1 -1");
return 0;
}