zoukankan      html  css  js  c++  java
  • 「CF585E」 Present for Vitalik the Philatelist

    「CF585E」 Present for Vitalik the Philatelist

    传送门

    我们可以考虑枚举 (S'=Scup{x}),那么显然有 (gcd{S'}=1)

    那么我们从里面可以选一个数出来作为 (x),共有 (|S'|) 种可能,我们记为 ((x,S))

    但是这样显然会计算到一些不合法的情况,考虑统计。

    对于一个集合 (S),若其 (gcd)(1),则再任意添加一个数 (gcd) 仍为 (1),这样的二元组显然是不合法的,共有 (n-|S|) 种可能。

    所以对于一个 (gcd)(1) 的集合 (S),其对答案的贡献就是 (|S|-(n-|S|)=2|S|-n)

    设给出的数的集合为 (U),故答案可表示为

    [sum_{Ssubseteq U,S eq varnothing}[gcd {S}=1](2|S|-n) ]

    显然可以考虑莫比乌斯反演,于是有

    [sum_{d}mu(d)sum_{Ssubseteq Ucap{x|x=kd,kin mathbb{Z}},S eq varnothing}(2|S|-n) ]

    (T=Ucap{x|x=kd,kin mathbb{Z}}),我们的问题就变为了计算

    [sum_{Ssubseteq T,S eq varnothing}(2|S|-n) ]

    首先这个不等于空集很烦,我们可以把它加上最后再减去,变为

    [n+2sum_{Ssubseteq T}|S|-sum_{Ssubseteq T}n ]

    后面那部分很好算,共有 (2^{|T|}) 种集合,答案即为 (2^{|T|}n)

    前一部分可以考虑计算每个数对答案的贡献,枚举选某个数(共 (|T|) 种可能),剩下的 (|T|-1) 个元素都是选或不选,故答案为 (2(2^{|T|-1}|T|)=2^{|T|}|T|)

    然后问题就变成了如何求 (T)

    这个东西可以直接分解质因数,也可以用 ( ext{Dirichlet}) 后缀和,在此不再赘述。

    总复杂度大概是 (O(Vlog_2log_2V+n)) 的,其中 (V) 表示值域。

    贴代码

    /*---Author:HenryHuang---*/
    /*---Never Settle---*/
    /*---Never Enough---*/
    #include<bits/stdc++.h>
    #define module(x) ((x)>=p?((x)-p):(x))
    using namespace std;
    const int maxn=1e7+5;
    const int p=1e9+7;
    int pri[maxn],pp[maxn],mu[maxn],cnt;
    int p2[maxn];
    int sum[maxn];
    void init(int mx){
    	mu[1]=1;
    	for(int i=2;i<=mx;++i){
    		if(!pp[i]) pri[++cnt]=i,mu[i]=-1;
    		for(int j=1;j<=cnt&&i*pri[j]<=mx;++j){
    			pp[i*pri[j]]=1;
    			if(i%pri[j]==0){
    				mu[i*pri[j]]=0;
    				break;
    			}
    			else mu[i*pri[j]]=-mu[i];
    		}
    	}
    }
    int main(){
    	ios::sync_with_stdio(0);
    	cin.tie(0),cout.tie(0);
    	int n;cin>>n;
    	p2[0]=1;
    	int mx=0;
    	for(int i=1;i<=n;++i){
    		int x;cin>>x;mx=max(mx,x);
    		++sum[x];
    		p2[i]=module(p2[i-1]<<1);
    	}
    	init(mx);
    	for(int i=1;i<=cnt;++i)
    		for(int j=mx/pri[i];j;--j)
    			sum[j]+=sum[j*pri[i]];
    	int ans=0;
    	for(int i=1;i<=mx;++i){
    		if(mu[i]){
    			int tmp=1ll*(1ll*p2[sum[i]]*(sum[i]-n+p)+n)%p;
    			if(mu[i]>0) ans=module(ans+tmp);
    			else ans=module(ans-tmp+p);
    		}
    	}
    	cout<<module(ans+p)<<'
    ';
    	return 0;
    }
    
    在繁华中沉淀自我,在乱世中静静伫立,一笔一划,雕刻时光。
  • 相关阅读:
    Python中如何调用Linux命令
    python入门小记
    DNS域名解析的过程
    阿里云Aliyun_server
    ipython及Python初体验
    js 的数值限制可能引起的问题
    页面图片中间有条线----解决
    ie6幽灵文字及解决办法
    解除工商银行15分钟限制
    ie6 无法显示网页 已终止操作
  • 原文地址:https://www.cnblogs.com/HenryHuang-Never-Settle/p/solution-CF585E.html
Copyright © 2011-2022 走看看