【CF1097F】Alex and a TV Show

【CF1097F】Alex and a TV Show

题面

洛谷

题解

我们对于某个集合中的每个\(i\),令\(f(i)\)表示\(i\)作为约数出现次数的奇偶性。

因为只要因为奇偶性只有\(0,1\)两种,我们考虑用\(bitset\)维护这个\(f\)

那么,

对于\(1\)操作你可以预处理一下\(v\)\(bitset\)

对于\(2\)操作就是两个集合的\(bitset\)异或一下,

对于\(3\)操作就是两个集合的\(bitset\)与一下。

最后我们要由\(f(i)\)推回\(i\)的出现次数,记为\(g(i)\),显然有

\[f(n)=\sum_{d|n} g(d)\]

莫比乌斯反演一下,

\[g(n)=\sum_{n|d} \mu (\frac dn) f(d)\]

你对于每个\(n\)\(n|d\)\(\mu (\frac dn)\bmod 2\)预处理出来放在一个\(bitset\)就好了。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring> 
#include <cmath> 
#include <algorithm> 
#include <bitset> 
using namespace std; 
inline int gi() {
    register int data = 0, w = 1;
    register char ch = 0; 
    while (!isdigit(ch) && ch != '-') ch = getchar(); 
    if (ch == '-') w = -1, ch = getchar(); 
    while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar(); 
    return w * data; 
} 
const int MAX_N = 1e5 + 5, MAX_M = 7005; 
bitset<MAX_M> bs[MAX_N], fact[MAX_M], mu[MAX_M], m; 
int N = 7000, Q; 
void Prepare() { 
    m.set(); 
    for (int i = 2; i * i <= N; i++) 
        for (int j = i * i; j <= N; j += i * i) m[j] = 0; 
    for (int i = 1; i <= N; i++) 
        for (int j = i; j <= N; j += i) fact[j][i] = 1, mu[i][j] = m[j / i]; 
} 

int main () {
#ifndef ONLINE_JUDGE 
    freopen("cpp.in", "r", stdin);
#endif
    Prepare(); 
    N = gi(), Q = gi(); 
    while (Q--) { 
        int op = gi(), x = gi(), y = gi(), z; 
        if (op == 1) bs[x] = fact[y]; 
        if (op == 2) z = gi(), bs[x] = bs[y] ^ bs[z]; 
        if (op == 3) z = gi(), bs[x] = bs[y] & bs[z]; 
        if (op == 4) printf("%lu", (bs[x] & mu[y]).count() & 1); 
    } 
    return 0; 
} 
posted @ 2019-11-04 15:58  heyujun  阅读(...)  评论(... 编辑 收藏