zoukankan      html  css  js  c++  java
  • CF1097F Alex and a TV Show(莫比乌斯反演+bitset)

    Description

    维护 \(n\) 个初始为空的可重集,支持以下操作(操作总次数为 \(q\)):

    1 x v : 令集合 \(x\) 等于 \(\left\{v\right\}\)

    2 x y z : 令集合 \(x\) 等于集合 \(y\)\(z\) 的并。

    3 x y z : 令集合 \(x\) 等于集合 \(y\)\(z\) 的积,\(A\times B=\left\{gcd(a,b)∣a∈A,b∈B\right\}\)

    4 x v : 询问 \(v\) 在集合 \(x\) 中出现次数模 \(2\) 的结果。

    \(1\leq n\leq 10^5,1\leq q\leq 10^6,1\leq v\leq 7000\)

    Solution

    对每个可重集 \(i\) 开一个 \(bitset\) : \(a[i]\)\(a[i][j]\) 表示第 \(i\) 个集合中 \(j\) 的倍数出现次数模 \(2\)

    1 x v :用 \(\mathcal O(\sqrt v)\) 的时间枚举 \(v\) 的约数 \(u\) 即可。

    2 x y z\(a[x]=a[y]\ \text{xor}\ a[z]\)\(\text{xor}\) 可以理解为模 \(2\) 意义下的加法。

    3 x y z\(a[x]=a[y]\ \text{and}\ a[z]\)\(\text{and}\) 可以理解为模 \(2\) 意义下的乘法。

    4 x v :设 \(f(n)\) 表示 \(n\) 在集合 \(x\) 中的出现次数,\(g(n)\) 表示 \(n\) 的倍数在集合 \(x\) 中的出现次数,那么有:$$g(n)=\sum_{n|d}f(d)⇔f(n)=\sum_{n|d}\mu(\frac{d}{n})g(d)$$

    那么对每个数 \(n\) 开一个 \(bitset\) : \(miu[n]\),其中 \(miu[n][d]=\mu(\lfloor\frac{d}{n}\rfloor)\% 2\)

    那么答案就是 \((a[x]\ \text{and}\ miu[v]).count()\)\(2\)

    时间复杂度 \(\mathcal O(q(\sqrt v+\frac{v}{64}))\)

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int m = 7e3, e = 1e5 + 5, o = 7e3 + 5;
    bitset<o>a[e], b[o];
    int miu[o], n, q;
    bool bo[o];
    
    template <class t>
    inline void read(t & res)
    {
        char ch;
        while (ch = getchar(), !isdigit(ch));
        res = ch ^ 48;
        while (ch = getchar(), isdigit(ch))
        res = res * 10 + (ch ^ 48);
    }
    
    inline void init()
    {
        int i, j;
        for (i = 1; i <= m; i++) miu[i] = 1;
        for (i = 2; i <= m; i++)
        if (!bo[i])
        {
            for (j = 2 * i; j <= m; j += i)
            {
                bo[j] = 1;
                if (j / i % i == 0) miu[j] = 0;
            }
        }
        for (i = 1; i <= m; i++)
        for (j = 1; i * j <= m; j++)
        b[i][i * j] = miu[j];
    }
    
    int main()
    {
        int op, x, y, z, v, i;
        read(n); read(q);
        init();
        while (q--)
        {
            read(op);
            if (op == 1)
            {
                read(x); read(v); a[x].reset();
                int s = sqrt(v);
                for (i = 1; i <= s; i++)
                if (v % i == 0) a[x][i] = a[x][v / i] = 1;
            }
            else if (op == 2)
            {
                read(x); read(y); read(z);
                a[x] = a[y] ^ a[z];
            }
            else if (op == 3)
            {
                read(x); read(y); read(z);
                a[x] = a[y] & a[z];
            }
            else
            {
                read(x); read(v);
                putchar((((a[x] & b[v]).count()) & 1) + 48);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    使用BeyondCompare作为Subversive的比较器
    Ubuntu下安装jdk6的方法和步骤
    推荐几款通用的数据库管理工具
    通用数据库都有哪些
    Linux下卸载ORACLE的多种方法(参考使用)
    jar包查询网站 非常好用!
    8种Nosql数据库系统对比
    SQL2005数据库镜像的步骤
    建立与删除SQL 2008事务复制发布
    同步复制JOB说明
  • 原文地址:https://www.cnblogs.com/cyf32768/p/12247164.html
Copyright © 2011-2022 走看看