Hello 2019 F (莫比乌斯反演 + bitset)
Posted virtu0s0
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hello 2019 F (莫比乌斯反演 + bitset)相关的知识,希望对你有一定的参考价值。
https://codeforces.com/contest/1097/problem/F
题意
有n个多重集,q次询问,4种询问
1. 将第x个多重集置为v
2. 将第y和z多重集进行并操作,并赋值给x
3. 将第y和z多重集进行乘操作,并赋值给x,乘操作:将y的每一个元素和z的每个元素的gcd放进多重集中
4. 询问第x个多重集中有多少个v,并将个数%2输出
题解
- 因为个数%2,所以可以考虑用bitset
- 操作1需要将一个数的因数放进x中,这样两个数相与就能得出两个数的公因数,方便操作3处理
- 操作2对两个集合进行异或即可
- 操作3对两个集合进行与就能得出两个集合所有数相互的公因数
- 假如a,b的公因数是x的倍数,那么gcd(a,b)一定是x的倍数
- \(g(n)=\sum_{n|d}f(d) =>f(n)=\sum_{n|d}\mu(\frac{d}{n})g(d)\),操作4需要先预处理出\(f(n)\),将\(f(n)\)放进一个多重集里,与x相与,然后x中1的个数就是答案
代码
#include<bits/stdc++.h>
#define M 7001
#define MAXN 100005
using namespace std;
bitset<M>miu[M];
bitset<M>a[MAXN];
int mu[M+5],pr[M],vi[M+5];
int n,q,x,v,y,z,kd,cnt;
void sieve(){
mu[1]=1;
for(int i=2;i<M;i++){
if(!vi[i]){mu[i]=-1;pr[++cnt]=i;}
for(int j=1;j<=cnt&&i*pr[j]<M;j++){
vi[i*pr[j]]=1;
if(i%pr[j]==0)break;
mu[i*pr[j]]=-mu[i];
}
}
for(int i=1;i<M;i++)
for(int j=i;j<M;j+=i)
if(mu[j/i])miu[i].set(j);
}
int main(){
sieve();
cin>>n>>q;
while(q--){
scanf("%d",&kd);
if(kd==1){
scanf("%d%d",&x,&v);
a[x].reset();
for(int i=1;i*i<=v;i++)
if(v%i==0){
a[x].set(i);a[x].set(v/i);
}
}
else if(kd==2){
scanf("%d%d%d",&x,&y,&z);
a[x]=a[y]^a[z];
}else if(kd==3){
scanf("%d%d%d",&x,&y,&z);
a[x]=a[y]&a[z];
}else{
scanf("%d%d",&x,&v);
bitset<M>tp=a[x]&miu[v];
printf("%d",tp.count()%2);
}
}
}
以上是关于Hello 2019 F (莫比乌斯反演 + bitset)的主要内容,如果未能解决你的问题,请参考以下文章