「LibreOJ β Round」ZQC 的截图(随机+hash)

https://loj.ac/problem/502

暴力的做法就是可持久化线段树,可惜空间爆了。

考虑给每个颜色随机一个权值,若到根路径的权值和是3的倍数,则说明这条路径可能所有颜色的出现次数是3的倍数。

一次的错误率是\(1/3\),显然太高了。
但我们可以多搞几维,把权值变成了\(w\)维的向量,则正确率是\((1-{1\over 3^w})^m\)

对于查询一个的,可以预先把每个颜色的1、2次的向量丢进一个hash表,每次查询即可,正确率\((1-{n\over 3^w})^m\)

\(w\)\(16*3\)时,可以用三个int压位存向量,可以预处理\(3^6*3^6\)的转移矩阵以加速向量不进位加法。

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;

#define gc getchar
template<class T> void read(T &x) {
	char c = ' '; x = 0; int f = 1;
	while((c < '0' || c > '9') && c != '-') c = gc();
	if(c == '-') f = -1, c = gc();
	for(; c >= '0' && c <= '9'; c = gc()) x = x * 10 + c - '0';
	x *= f;
}

const int w = 729;

int a3[7];

int ja[w][w];

struct P {
	int x, y, z;
	P(int _x = 0, int _y = 0, int _z = 0) {
		x = _x, y = _y, z = _z;
	}
};

void build() {
	a3[0] = 1; fo(i, 1, 6) a3[i] = a3[i - 1] * 3;
	ff(i, 0, w) ff(j, 0, w) {
		int s = 0;
		ff(k, 0, 6) {
			int x = (i / a3[k] % 3 + j / a3[k] % 3) % 3;
			s += x * a3[k];
		}
		ja[i][j] = s;
	}
}

int calc(int x, int y) {
	return ja[x / w / w][y / w / w] * w * w + ja[x / w % w][y / w % w] * w + ja[x % w][y % w];
}

P operator + (P a, P b) {
	return P(calc(a.x, b.x), calc(a.y, b.y), calc(a.z, b.z));
}

bool operator == (P a, P b) {
	return a.x == b.x && a.y == b.y;
}

int rd() {
	return rand() % w * w * w + rand() % w * w + rand() % w;
}

const int N = 2e6 + 5;

int n, m;
P f[N], g[N * 2];

const int M = 7260718;

int h[M];

int ha(P a) {
	int y = (a.x + a.y) % M;
	while(h[y] != 0 && !(f[h[y]] == a))	
		y = (y + 1) % M;
	return y;
}

int main() {
	srand(time(0) + clock());
	build();
	scanf("%d %d", &n, &m);
	fo(i, 1, n) {
		f[i] = P(rd(), rd(), rd());
		f[n + i] = f[i] + f[i];
		int y = ha(f[i]);
		h[y] = i;
		y = ha(f[n + i]);
		h[y] = n + i;
	}
	int ans = 0;
	fo(i, 1, m) {
		int x, y;
		read(x); read(y);
		x ^= ans, y ^= ans;
		g[i] = g[y] + f[x];
		if(g[i].x == 0 && g[i].y == 0) {
			ans = -1;
		} else {
			int y = ha(g[i]);
			if(h[y]) {
				ans = h[y] > n ? h[y] - n : h[y];
			} else ans = -2;
		}
		pp("%d\n", ans);
	}
}
posted @ 2020-04-08 13:35  Cold_Chair  阅读(242)  评论(0编辑  收藏  举报