[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("
")
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
", i, x); else
				pp("%d %d
", 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
");
}
原文地址:https://www.cnblogs.com/coldchair/p/12809870.html