[NOI2013] 向量内积(随机好题)
https://www.luogu.com.cn/problem/P1224
先考虑\(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的错误概率是\(1/2\)。
所以做\(T=10\)次,时间复杂度:\(O(T*n*d)\)
\(k=3\)时,就不能这么做了,因为点积不为0时可以为1、2
取点积的平方,一定就\(=1\)了,可以把式子拆开以快速计算点积的平方。
这里复杂度就是:\(O(T*n*d^2)\)
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i < _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;
const int N = 1e5 + 5;
int n, d, mo, a[N][100], b[100], c[100][100];
int p[N];
void check(int x) {
fo(i, 1, n) if(i != x) {
int s = 0;
ff(j, 0, d) s += a[x][j] * a[i][j];
s %= mo;
if(s == 0) {
if(i < x) pp("%d %d\n", i, x); else
pp("%d %d\n", x, i);
exit(0);
}
}
}
int main() {
srand(19260817);
scanf("%d %d %d", &n, &d, &mo);
fo(i, 1, n) {
ff(j, 0, d) {
scanf("%d", &a[i][j]);
a[i][j] %= mo;
}
}
fo(i, 1, n) p[i] = i;
fo(T, 1, 10) {
random_shuffle(p + 1, p + n + 1);
ff(j, 0, d) b[j] = 0;
fo(i, 1, n) {
int s = 0;
if(mo == 2) {
ff(j, 0, d) s += b[j] * a[p[i]][j];
} else {
ff(j, 0, d) ff(k, 0, d) s += c[j][k] * a[p[i]][j] * a[p[i]][k];
}
s %= mo;
if(s != (i - 1) % mo) {
check(p[i]);
}
if(mo == 2) {
ff(j, 0, d) b[j] = (b[j] + a[p[i]][j]) % mo;
} else {
ff(j, 0, d) ff(k, 0, d) c[j][k] = (c[j][k] + a[p[i]][j] * a[p[i]][k]) % mo;
}
}
}
pp("-1 -1\n");
}
转载注意标注出处:
转自Cold_Chair的博客+原博客地址