[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");
}
posted @ 2020-04-30 17:04  Cold_Chair  阅读(370)  评论(0编辑  收藏  举报