题解 CF1746F Kazaee
题意
给定一个长度为 $n$ 的序列 $a$,$m$ 次操作:
- 将 $a_i$ 修改为 $x$。
- $\forall x \text{ appear in}\left[l,r\right]$,计 $cnt_x$ 为 $x$ 在 $\left[l,r\right]$ 中的出现次数,查询 $cnt_x$ 是否均为 $k$ 的倍数。
数据范围:$1\le n,m\le 3\times 10^5, 1\le a_i,x\le10^9$
题解
显然有一个 $O(n^{\frac{5}{3}}\log n)$ 的带修莫队做法,当然过不了。
因为有神秘人告诉我,这题和 CSP 2022 的 C 类似,想到赋随机值哈希。
考虑把查询转化为区间和,发现区间和是 $k$ 的倍数答案为 YES 的必要条件,给每个 $a_i$ 映射到随机值 $b_i$ 上,bit 维护 $b_i$ 前缀和。
这种算法在 $k$ 很小时,正确性不高,因为 $b_i$ 是随机的,所以区间和也是随机的,当答案为 NO 且区间和为 $k$ 的倍数的概率是 $\frac{1}{k}$,可以考虑多随几组,$k=1$ 时答案肯定为 YES,$k\ge 2$ 时,随 $T$ 组错误的概率 $\le\frac{1}{2^T}$,对于所有询问错误率 $\le \frac{m}{2^T}$,当 $T=40$,这个错误率已经极小了,可以接受。
时间复杂度 $O(Tn\log n)$,其中 $T=40$。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 3e5 + 10;
mt19937_64 R;
int Rand(int l, int r) {
uniform_int_distribution<int> distribution(l, r);
return distribution(R);
}
int n, m, a[N], lsh[N << 1], cnt;
int rnd[N << 1], b[N];
bool ans[N];
struct query {
int opt, x, y, k;
} q[N];
namespace bit {
ll t[N];
void add(int x, int k) {
for(int i = x; i <= n; i += i & -i)
t[i] += k;
}
ll qry(int x) {
ll res = 0;
for(int i = x; i; i -= i & -i)
res += t[i];
return res;
}
ll qry(int l, int r) {
return qry(r) - qry(l - 1);
}
} using namespace bit;
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]), lsh[++cnt] = a[i];
for(int i = 1; i <= m; i++) {
scanf("%d%d%d", &q[i].opt, &q[i].x, &q[i].y);
if(q[i].opt == 1) lsh[++cnt] = q[i].y;
else scanf("%d", &q[i].k);
}
sort(lsh + 1, lsh + 1 + cnt);
cnt = unique(lsh + 1, lsh + 1 + cnt) - lsh - 1;
for(int i = 1; i <= n; i++)
a[i] = lower_bound(lsh + 1, lsh + 1 + cnt, a[i]) - lsh;
for(int i = 1; i <= m; i++)
if(q[i].opt == 1) q[i].y = lower_bound(lsh + 1, lsh + 1 + cnt, q[i].y) - lsh;
memset(ans, 1, sizeof(ans));
for(int T = 1; T <= 40; T++) {
memset(t, 0, sizeof(t));
for(int i = 1; i <= cnt; i++)
rnd[i] = Rand(1, 1e9);
for(int i = 1; i <= n; i++)
b[i] = a[i];
for(int i = 1; i <= n; i++)
add(i, rnd[a[i]]);
for(int i = 1; i <= m; i++) {
if(q[i].opt == 1) {
add(q[i].x, -rnd[b[q[i].x]]);
b[q[i].x] = q[i].y;
add(q[i].x, rnd[b[q[i].x]]);
}
else ans[i] &= (qry(q[i].x, q[i].y) % q[i].k == 0);
}
}
for(int i = 1; i <= m; i++)
if(q[i].opt == 2) puts(ans[i] ? "YES" : "NO");
return 0;
}

浙公网安备 33010602011771号