CF1097F Alex and a TV Show
题意
维护n个初始为空的可重集,支持以下操作:
1 x v:令集合x等于{v}
2 x y z:令集合x等于集合y与z的并
3 x y z:令集合x等于集合y与z的积,A*B = {gcd(a,b)∣a∈A,b∈B}
4 x v:询问v在集合x中出现次数模2的结果
权值小于7000,n<=1e6
题解
题目只关注每个数的出现次数
而对于v在集合x中的出现次数,我们发现可以通过莫比乌斯反演变成一个有关x的约数的出现次数和莫比乌斯函数的式子
而我们只关注答案的奇偶性,所以可以转换为2进制
考虑对每个集合开个bitset,对每个集合存数x的约数出现次数
此时对于操作3和4只需要xor和and
对于操作1预处理即可
代码如下:
#include<bits/stdc++.h> #define LL long long using namespace std; inline LL read() { LL f = 1 , x = 0; char ch; do { ch = getchar(); if(ch=='-') f=-1; } while(ch<'0'||ch>'9'); do { x=(x<<3) + (x<<1) + ch - '0'; ch = getchar(); }while(ch>='0'&&ch<='9'); return f*x; } const int MAXN = 7000 + 10; const int N = 100000 + 10; bool isprime[MAXN + 500]; int mu[MAXN],prime[MAXN],tot; bitset<7010>a[N],b[MAXN],u[MAXN]; inline void pre() { mu[1] = 1; for(int i=2;i<MAXN;i++) { if(!isprime[i]) { prime[++tot] = i; mu[i] = -1; } for(int j=1;j<=tot&&i*prime[j]<MAXN;j++) { isprime[i*prime[j]] = 1; if(i%prime[j]==0) { break; } mu[i*prime[j]] = -mu[i]; } } } int n,q; int main() { pre(); for(int i=1;i<MAXN;i++) { for(int j=1;i*j<MAXN;j++) { b[i*j][i] = 1; u[i][i*j] = abs(mu[j]); } } n = read(),q = read(); for(int i=1;i<=q;i++) { int opt = read(); if(opt==1) { int x = read(),v = read(); a[x] = b[v]; } if(opt==2) { int x = read(),y = read(),z = read(); a[x] = a[y] ^a[z]; } if(opt == 3) { int x = read(),y = read(),z = read(); a[x] = a[y] & a[z]; } if(opt == 4) { int x = read(),v = read(); printf("%d",(a[x]&u[v]).count()&1); } } }