一、随机化避免碰撞
1.对数字进行随机化后可以避免数字发生碰撞。
这道题的唯一难点是判断一个房间里的一群人是否出现过。
可以考虑对于每一个人赋予他一个rand值,然后用rand值的和判断是否出现过。
比如有编号1,2,3的三个人,假设他们的rand值为11,45,14
1和2同时出现的时候他们的rand值之和sum_rand=56而他们的编号之和sum_pos=3
发现sum_rand!=rand[3]但是sum_pos=pos[3]
用rand有效的减小了碰撞的概率。
那么这道题的思路就非常简单了。
map<int, int> vis; set<int> s; int a[MAXN], to[MAXN], n, m, q, num[MAXN], h[MAXN]; signed main() { srand(2004 + 8 + 21); n = read(), m = read(), q = read(); for (int i = 1; i <= n; i++) { a[i] = rand() * rand() % 1145141919 * (rand() * rand() % 19260817) * 810; h[1] ^= a[i]; to[i] = 1; num[1]++; } s.insert(1); while (q--) { char opt; cin >> opt; int x = read(), y = read(); if (opt == 'C') { if (to[x] == y) continue; s.erase(to[x]); s.erase(y); h[to[x]] ^= a[x]; h[y] ^= a[x]; num[to[x]]--; num[y]++; if (!vis[h[to[x]]]) s.insert(to[x]); if(!vis[h[y]]) s.insert(y); to[x] = y; } if (opt == 'W') { int ans = 0; auto it = s.lower_bound(x); for (; it != s.end() && *it <= y; it = s.lower_bound(x)) { vis[h[*it]] = 1; ans += num[*it]; s.erase(it); } cout << ans; puts(""); } } return 0; }
2.多次随机化避免碰撞
例题: P2312 解方程
直接算会溢出,可以随机取几个模数,
对于一个数x如果取模后计算出来的方程结果是0,那么这个x就是一个答案。
int n, m, a[MAXN], k[MAXN], cnt, t, ans, sum; int calc(int x, int MOD) { sum = 0; for (int i = n; i >= 1; i--) { sum = ((sum + a[i]) * x) % MOD; } sum = (sum + a[0]) % MOD; return !sum; } signed main() { n = read(), m = read(); for (int i = 0; i <= n; i++) { a[i] = read(); } for (int i = 1; i <= m; i++) { if (calc(i,rand())&&calc(i,rand())) { t = 1; ans++; k[++cnt] = i; } } if (!t) { puts("0"); return 0; } printf("%lld", ans); puts(""); for (int i = 1; i <= cnt; i++) { printf("%lld", k[i]); puts(""); } return 0; }