• 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 imes B = { gcd(a, b)\, mid\, a in A,\, b in B }),结果也是一个可重集。
    4. (4 x v)。求第 (x) 个可重集里数值 (v) 出现的次数在 (mod 2) 意义下的结果。

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

    数据范围:(1leq nleq 10^5)(1leq qleq 10^6)(1leq vleq 7000)

    本题题解

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

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

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

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

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

    考虑操作 1。可以对每个数值 (v),预处理出集合 ({v}) 所对应的 (g)(g(x) = [x|v]))。则操作 1 就是将一个 ( exttt{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),预处理一个 ( exttt{bitset})(mathrm{coef}_v),表示求答案时每个数字对应的系数。则:(mathrm{ans}(i, v) = mathrm{bitcnt}(g_ioperatorname{and} mathrm{coef}_v)mod 2)

    总时间复杂度 (mathcal{O}(dlog d + q cdotfrac{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;
    }
    
  • 相关阅读:
    linux学习之centos(四):git的安装
    MongoDB学习
    linux学习之centos(三):mysql数据库的安装和配置
    面经中高频知识点归纳(三)
    各编程语言的内存分配方式
    carson常用linux命令整理
    在 Linux 虚拟机中手动安装或升级 VMware Tools
    Fidder 网络抓包调试工具
    面经中高频知识点归纳(二)
    java集合类
  • 原文地址:https://www.cnblogs.com/dysyn1314/p/14520665.html
Copyright © 2020-2023  润新知