• #并查集,线性筛#nssl 1470 X


    题目


    分析

    显然答案就是(2^{连通块个数}-2),

    将每个数的质数所在的集合合并,

    最后判断连通块个数即可(线性筛少了个等号改了半天QWQ)


    代码

    #include <cstdio>
    #include <cctype>
    #define rr register
    using namespace std;
    const int N=1e5+1,M=1e6,mod=1e9+7;
    int two[N],prime[N],v[N*10],f[N],a[N],n,Cnt,ans;
    inline signed iut(){
    	rr int ans=0; rr char c=getchar();
    	while (!isdigit(c)) c=getchar();
    	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    	return ans;
    }
    inline void print(int ans){
    	if (ans>9) print(ans/10);
    	putchar(ans%10+48);
    }
    inline signed mo(int x,int y){return x+y>=mod?x+y-mod:x+y;}
    inline signed getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
    signed main(){
    	for (rr int i=2;i<=M;++i){
    		if (!v[i]) prime[++Cnt]=i,v[i]=Cnt;
    		for (rr int j=1;j<=Cnt&&i<=M/prime[j];++j){
    			v[i*prime[j]]=j;
    			if (i%prime[j]==0) break;
    		}
    	}
    	two[0]=1;
    	for (rr int i=1;i<N;++i)
    	    two[i]=mo(two[i-1],two[i-1]);
    	for (rr int T=iut();T;--T){
    		ans=n=iut();
    		for (rr int i=0;i<=Cnt;++i) f[i]=i;
    		for (rr int i=1;i<=n;++i){
    			a[i]=iut();
    			for (rr int j=a[i],last=0;j>1;){
    				rr int now=v[j];
    				if (last){
    					rr int fa=getf(last),fb=getf(now);
    					if (fa>fb) fa^=fb,fb^=fa,fa^=fb;
    					if (fa!=fb) f[fa]=fb;
    				}
    				while (j%prime[now]==0) j/=prime[now];
    				last=now;
    			}
    		}
    		for (rr int i=1;i<=n;++i)
    		if (a[i]>1){
    			rr int F=getf(v[a[i]]);
    			if (!F) --ans; else f[F]=0;
    		}
    		print(mo(two[ans],mod-2)),putchar(10);
    	}
    	return 0;
    } 
    
  • 相关阅读:
    小技巧
    常用的交互设计软件
    Android studio 使用SVN需要忽略的文件
    android studio 使用SVN 锁定文件,防止别人修改(基于Android studio 1.4 )
    git 和 github 关系?
    Double 数据保留两位小数一:五舍六入
    设计模式
    Java中关于日期类那些方法
    ios 开源免费接口
    华为招聘机试整理5:简单四则运算
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/13498872.html
Copyright © 2020-2023  润新知