CF1097F Alex and a TV Show

CF1097F Alex and a TV Show

题目大意

题目链接

\(n\) 个可重集,初始时均为空。接下来进行 \(q\) 次操作。操作有如下四种:

  1. \(1\ x\ v\),将第 \(x\) 个可重集设为 \(\{v\}\)
  2. \(2\ x\ y\ z\),将第 \(x\) 个可重集设为第 \(y\) 个可重集和第 \(z\) 个可重集的并。
  3. \(3\ x\ y\ z\),将第 \(x\) 个可重集设为第 \(y\) 个可重集和第 \(z\) 个可重集的乘积。两个可重集 \(A,B\) 的乘法定义为:\(A\times B = \{ \gcd(a, b)\, \mid\, a \in A,\, b \in B \}\),结果也是一个可重集。
  4. \(4\ x\ v\)。求第 \(x\) 个可重集里数值 \(v\) 出现的次数在 \(\bmod 2\) 意义下的结果。

\(x, y, z\) 可能相同。

数据范围:\(1\leq n\leq 10^5\)\(1\leq q\leq 10^6\)\(1\leq v\leq 7000\)

本题题解

\(d\) 表示涉及数值的最大值,本题里 \(d\leq 7000\)

因为只需要求 \(\bmod 2\) 意义下的答案,容易想到用 \(\texttt{bitset}\) 存储每个值出现的次数的奇偶性。具体来说,设 \(f_i(x)\) 表示在第 \(i\) 个可重集里,数值 \(x\) 出现的次数的奇偶性。那么操作 2 就是将两个 \(\texttt{bitset}\)\(\operatorname{xor}\),单次操作的时间复杂度为 \(\mathcal{O}(\frac{d}{\omega})\),其中 \(\omega\) 是位长,可以认为 \(\omega = 64\)。但是操作 3 则难以快速实现。

考虑 FFT 算法的思想,将难以计算的东西转化为“点值”,对点值进行运算,再通过逆操作还原回去。设 \(g_i(x) = (\sum_{x | y} f_i(y))\bmod 2\),也就是【\(x\) 的所有倍数的出现次数之和】的奇偶性。注意到,\(\gcd(a, b)\)\(x\) 的倍数,当且仅当 \(a, b\) 都是 \(x\) 的倍数。因此在操作 3 的结果集合中 \(x\) 的倍数的出现次数,就是两个被操作集合中 \(x\) 的倍数的出现次数的乘积。于是操作 3 可以转化为将两个 \(\texttt{bitset}\)\(g\))做 \(\operatorname{and}\),这部分时间复杂度 \(\mathcal{O}(\frac{d}{\omega})\)

但是我们还需要从 \(f\) 推出 \(g\),从 \(g\) 还原回 \(f\),这两个过程都是 \(\mathcal{O}(d\log d)\) 的,太慢了。考虑不维护 \(f\),直接对 \(g\) 进行运算,并通过 \(g\) 回答询问。

操作 2 对 \(g\) 的影响同样是把两个 \(\texttt{bitset}\)\(\operatorname{xor}\)

考虑操作 1。可以对每个数值 \(v\),预处理出集合 \(\{v\}\) 所对应的 \(g\)\(g(x) = [x|v]\))。则操作 1 就是将一个 \(\texttt{bitset}\) 赋值为另一个,时间复杂度 \(\mathcal{O}(\frac{d}{\omega})\)

考虑回答询问:已知所有数值 \(x\)倍数的出现次数,求给定的数值 \(v\) 的出现次数。用莫比乌斯反演:\(g(x) = \sum_{x | y}f(y)\Leftrightarrow f(x) = \sum_{x | y} \mu(\frac{y}{x})g(y)\)。也就是对 \(v\) 的所有倍数,乘以一个系数(\(\mu(\frac{y}{v})\))后相加。可以对所有数值 \(v\),预处理一个 \(\texttt{bitset}\)\(\mathrm{coef}_v\),表示求答案时每个数字对应的系数。则:\(\mathrm{ans}(i, v) = \mathrm{bitcnt}(g_i\operatorname{and} \mathrm{coef}_v)\bmod 2\)

总时间复杂度 \(\mathcal{O}(d\log d + q \cdot\frac{d}{\omega})\)。空间复杂度 \(\mathcal{O}((n + d)\frac{d}{\omega})\)

参考代码

实际提交时建议使用读入、输出优化,详见本博客公告。

// problem: CF1097F
#include <bits/stdc++.h>
using namespace std;

#define mk make_pair
#define fi first
#define se second
#define SZ(x) ((int)(x).size())

typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;

template<typename T> inline void ckmax(T& x, T y) { x = (y > x ? y : x); }
template<typename T> inline void ckmin(T& x, T y) { x = (y < x ? y : x); }

const int MAXN = 1e5, MAXD = 7000;

int n, q;

int p[MAXD + 5], cnt_p, mu[MAXD + 5];
bool v[MAXD + 5];

bitset<MAXD + 5> st[MAXD + 5], coef[MAXD + 5], g[MAXN + 5];

void init(int d) {
	mu[1] = 1;
	for (int i = 2; i <= d; ++i) {
		if (!v[i]) {
			p[++cnt_p] = i;
			mu[i] = -1;
		}
		for (int j = 1; j <= cnt_p && p[j] * i <= d; ++j) {
			v[p[j] * i] = 1;
			if (i % p[j] == 0)
				break;
			mu[p[j] * i] = -mu[i];
		}
	}
	
	for (int i = 1; i <= d; ++i) {
		for (int j = i; j <= d; j += i) {
			st[j][i] = 1;
			coef[i][j] = (mu[j / i] + 2) % 2;
		}
	}
}

int main() {
	init(MAXD);
	cin >> n >> q;
	while (q--) {
		int op, x, y, z;
		cin >> op;
		if (op == 1) {
			cin >> x >> y;
			g[x] = st[y];
		} else if (op == 2) {
			cin >> x >> y >> z;
			g[x] = (g[y] ^ g[z]);
		} else if (op == 3) {
			cin >> x >> y >> z;
			g[x] = (g[y] & g[z]);
		} else {
			cin >> x >> y;
			int ans = (g[x] & coef[y]).count() % 2;
			cout << ans;
		}
	}
	return 0;
}
posted @ 2021-03-11 21:25  duyiblue  阅读(124)  评论(2编辑  收藏  举报