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
考虑到正经做法不是很好做,考虑不太正经的做法。
首先可以发现 (kle 3),那么先考虑 (k=2) 时候的情况。可以发现,如果对于 (i) 存在:
[sum_{j=1}^{i-1}|x_i·x_j|
otequiv i-1 pmod 2
]
就说明一定存在一个解了。正确概率不是很会算。快速算的话,可以对向量做个前缀和。
考虑 (k=3) ,你发现 (x^{k-1}equiv pmod k) ( (k) 为质数),所以如果对于 (i) 存在:
[sum_{j=1}^{i-1}|x_i·x_j|^2
otequiv i-1pmod 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 ('
');
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 ('
');
return 0;
}
}
}
}
}
puts ("-1 -1");
return 0;
}