兩個
d 維向量 a=
[a1,
a2,…
,ad]
與 b=[
b1,b
2,…,
bd] 的內積為其相對應維度的權值的乘積和,即:⟨a
,b⟩=
∑i=1
daib
i=a1
b1+a
2b2+
⋯+ad
bd現在有
n 個
d維向量 x1
,x2,
…,xn
,小喵喵想知道是否存在兩個向量的內積為
k 的倍數。請幫助她解決這個問題。
第一行包含
3個正整數 n,
d,k ,分別表示向量的個數,維數以及待檢測的倍數。
接下來
n 行每行有
d個非負整數,其中第
i 行的第
j個整數表示向量 xi
的第 j 維權值 xi
,j。包含兩個整數,用空格隔開。
如果存在兩個向量 xp
,xq 的內積為
k 的整數倍,則輸出兩個向量的編號 p與
q (要求
p<
q)。如果存在多組這樣的向量組合,輸出其中任意一組即可。
若不存在這樣的向量組合,則輸出兩個 −1
。input
3 5 2output1 0 1 0 1
1 1 0 1 0
0 1 0 1 1
2 3explanation⟨x
1,x2
⟩=1 ,⟨x
1,x3
⟩=1 ,⟨x
2,x3
⟩=2 。
測試點編號
n dk
xi,j12
202≤10
25202
≤10310
20
3 ≤10
42020
2
≤100550
20
3
≤100650
50
2
≤1000750
50
3
≤3000000880
80
2
≤3000000
9100
100
3
≤3000000
10500
100
3
≤3000000
111000
100
2
≤3000000
121000
100
3
≤3000000
1310000
100
2
<
1014
10000
100
3
<
1015
15000
100
2
<
1016
18000
100
2
<
1017
20000
100
2
<
1018
50000
30
3
<
1019
80000
30
3
<
1020
100000
30
3
<10
時間限制:5s
空間限制:
256mb
注意:以下運算都在模k意義下
我們把這些向量看成乙個n×
d 的矩陣a
a=⎡⎣
⎢⎢⎢⎢
⎢x1,
1x2,
1⋮xn
,1x1
,2x2
,2⋮x
n,2x
1,3x
2,3⋮
xn,3
⋯⋯⋱⋯
x1,d
x2,d
⋮xn,
d⎤⎦⎥
⎥⎥⎥⎥
a 的轉置矩陣at
=⎡⎣⎢
⎢⎢⎢⎢
x1,1
x1,2
⋮x1,
nx2,
1x2,
2⋮x2
,nx3
,1x3
,2⋮x
3,n⋯
⋯⋱⋯x
n,1x
n,2⋮
xnn⎤
⎦⎥⎥⎥
⎥⎥令b
=a×a
t ,那麼bi
,j就表示xi
⋅xj ,如果
b 矩陣除了主對角線全部是1的話,顯然無解。
但是求出
b矩陣的時間顯然是o(
n2d)
,顯然是無法通過本題的。
我們令b
′ 為bi
,i=x
i⋅xi
,其餘元素為1的矩陣。 如果b
=b′的話,就無解。
我們再隨機找出乙個列向量
c (其實就是全是1,因為0沒用。。。)b×
c=b′
×ca×
at×c
=b′×
ca×(
at×c
)=b′
×cd=
at×c
我們可以用o(
nd) 的時間求出來,a×
d 也可以用o(
nd) 的時間求出來,b′
×c可以o(
n)求出。
然後比較a×
(at×
c)b′
×c這兩個列向量的每乙個元素是否相同,如果第i行的元素不相同,說明xi
肯定是答案只要,列舉找出xj
即可。
儘管有出錯的概率,但是這個演算法還是比較可靠的。
我們發現1×
1≡2×
2≡1(
mod3)
所以,我們令b=
(a∗a
t)2 其餘矩陣定義不變,那麼展開後會發現 a′
=⎡⎣⎢
⎢⎢⎢⎢
x1,1
×x1,
1x2,
1×x2
,1⋮x
n,1×
xn,1
x1,1
×x1,
2x2,
1×x2
,2⋮x
n,1×
xn,2
x1,1
×x1,
3x2,
1×x2
,3⋮x
n,1×
xn,3
⋯⋯⋱⋯
x1,1
×x1,
dx2,
1×x2
,d⋮x
n,1×
xn,d
x1,2
×x1,
1x2,
2×x2
,1⋮x
n,2×
xn,1
x1,2
×x1,
2x2,
2×x2
,2⋮x
n,2×
xn,2
⋯⋯⋱⋯
x1,d
×x1,
dx2,
d×x2
,d⋮x
n,d×
xn,d
⎤⎦⎥⎥
⎥⎥⎥b
=a′×
a′t
然後參考k=
2 的演算法即可,由於k=
3 時矩陣太大,記憶體開不下,但是算的時候按照規則算就行了。
#include
#include
using
namespace
std;
#define maxn 100000
#define maxm 100
int n,d,k,a[maxn+10][maxm+10],s[maxn+10],c[maxm*maxm+10],g[maxn+10];
void read(int &x)
}int get_id(int i,int j)
void read()
for(i=1;i<=n;i++)
s[i]%=k;
}void solve2()
for(j=1;j<=n;j++)
if(i!=j)
if(i>j)
swap(i,j);
printf("%d %d\n",i,j);
}void solve3()
for(j=1;j<=n;j++)
if(j!=i)
if(i>j)
swap(i,j);
printf("%d %d\n",i,j);
}int main()
NOI2013 向量內積
題面 題解窩本來想用這道題寫矩陣雜湊的,所謂矩陣雜湊,就是快速判斷兩個矩陣的乘積是不是另外乙個矩陣。矩陣雜湊就是隨機乙個向量,利用矩陣結合律先算向量和各矩陣的乘積,然後直接比較兩個向量是不是相等的。這樣本來是 n 3 的,就變成 n 2 的。但是看到題解第一種方法更簡便而且更易懂,就寫第一種方法了。...
NOI2013 向量內積
定義兩個 d 維向量 的內積為其相對應維度的權值的乘積和 a i b i 現在有 n 個 d 維向量,判斷是否存在兩個向量的內積為 k 的倍數 我們考慮將 n 個 d 維的向量構成乙個 n d 的矩陣 a a 為 a 的轉置矩陣。令矩陣 那麼 就表示了向量 i 與向量 j 的內積。直接判斷內積的值即...
NOI2013 向量內積(隨機好題)
先考慮 k 2 怎麼做。注意到點積不為0就為1。我們隨機乙個排列 p i 然後列舉 i 1 n 看看 p i 與 p 1.i 1 的點積和 s 如果 s i 1 mod k 則說明 p 1.i 1 中一定有乙個向量和 p i 的點積 0 此時暴力check就行了。最壞情況一次check的錯誤概率是 ...