zoukankan      html  css  js  c++  java
  • Codeforces 839D Winter is here

    链接:CF839D

    题目大意

    给定一个数组大小为(n(1leq nleq 200000))的数组(a),满足(1leq a_i leq 1000000)

    选择其中任意(len)个数字,若(gcd>1),则该组数字对答案贡献为(len*gcd),求最终答案对(1e9+7)取模。

    题目分析

    因为(gcd)的本质是因数分解,可以想到,如果不考虑算重,那么:

    对于一个(gcd)的结果(x),若有(num)个数含有(x)这个因数,则被选择的数可形成的形如(gcd(...)==x)的贡献为:

    ((1*C_{num}^1+2*C_{num}^2+3*C_{num}^3+......+num*C_{num}^{num})*x)

    其中,(num)可以直接枚举得到:

    (for(int i=x;i<=1000000;i+=x)num[x]+=cnt[i];)

    (cnt[i])表示(a[ ])中大小为(i)的数字的个数,由于时间复杂度是调和级数,可以(O(nlog(n)))求解。

    由公式可得:

    (1*C_{n}^1+2*C_{n}^2+3*C_{n}^3+......+n*C_{n}^{n}=n*2^{n-1})

    此处可以(O(1))求得答案,总时间复杂度为(O(nlog(n)))


    由于会有重复的情况,我们可以使用容斥去重。

    对于每个数的容斥系数,可以附初值:(tmp[i]=i;)

    由于每个数会在它的因数部分算重,可得:

    (tmp[x]=x- sumlimits_{d|x}tmp[d];)

    (tmp)数组的计算也是调和级数,可以在(O(nlog(n)))求解。


    综上:

    (ans+=num[x]*2^{num[x]-1}*x*tmp[x];)

    总时间复杂度(O(nlog(n)))

    代码实现

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<cstdio>
    #include<iomanip>
    #include<cstdlib>
    #define MAXN 0x7fffffff
    typedef long long LL;
    const int N=1000005,mod=1e9+7;
    using namespace std;
    inline int Getint(){register int x=0,f=1;register char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}return x*f;}
    int tmp[N],prime[N];
    bool vis[N];
    void Pre(int n){
    	for(int i=2;i<=n;i++)tmp[i]=i;
    	for(int i=2;i<=n;i++){
    		if(!vis[i])prime[++prime[0]]=i,vis[i]=1;
    		for(int j=1;j<=prime[0]&&1ll*i*prime[j]<=n;j++){
    			vis[i*prime[j]]=1;
    			if(i%prime[j]==0)break;
    		}
    		for(int j=2;1ll*i*j<=n;j++)tmp[j*i]-=tmp[i];
    	}
    } 
    LL ksm(LL x,LL k){
    	LL ret=1;
    	while(k){
    		if(k&1)ret=ret*x%mod;
    		x=x*x%mod;
    		k>>=1; 
    	} 
    	return ret;
    }
    int cnt[N];
    int Query(int x){
    	int ret=0;
    	for(int i=x;i<=1000000;i+=x)ret+=cnt[i];
    	return ret;
    }
    int main(){
    	Pre(1000000);
    	int n=Getint();
    	for(int i=1;i<=n;i++)cnt[Getint()]++;
    	LL ans=0;
    	for(int i=2;i<=1000000;i++){
    		int x=Query(i);
    		if(!x)continue;
    		ans=(ans+x*ksm(2,x-1)%mod*tmp[i]%mod)%mod;
    	}
    	cout<<(ans+mod)%mod;
    	return 0;
    }
    
    
  • 相关阅读:
    vue中路由跳转传递参数
    父组件向子孙组件传递数据provide/inject
    微信、QQ等内置浏览器定位失败
    Java ArrayList类
    java 生成 [1, n] 之间的随机数
    Java 构造方法
    Java this关键字
    Java private关键字及作用
    Java 随笔
    Java 内存划分
  • 原文地址:https://www.cnblogs.com/Emiya-wjk/p/9991117.html
Copyright © 2011-2022 走看看