zoukankan      html  css  js  c++  java
  • 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);
    		}
    	}
    }
    
  • 相关阅读:
    Array的应用
    事物的操作
    定义集合
    wxWidgets 在 Linux 下开发环境配置
    Emacs 中 GDB 的使用
    wxWidgets 在 Windows 下开发环境配置
    Ubuntu14.04终端主机名+用户名修改配色方案
    S5PV210之内外存学习
    Ubuntu14.04进行配置符号链接arm2009q3.tar.bz2
    Ubuntu14.041+VMware12.0NET方式网卡连接虚拟机联网问题解决方法
  • 原文地址:https://www.cnblogs.com/VIrtu0s0/p/10807649.html
Copyright © 2011-2022 走看看