zoukankan      html  css  js  c++  java
  • Codeforces 585E. Present for Vitalik the Philatelist 题解

    题目链接:E. Present for Vitalik the Philatelist

    题目大意:洛谷


    题解:设(g_i)表示又多少个数与(i)互质,(f_i)表示有多少个集合的(gcd)恰好为(i)。那么最终的答案就是(sum_{ige 2} f_i imes g_i)

    先考虑如何算(g),将式子列出来(令(c_i)表示(i)的出现次数):

    [g_i=sum_{j=1} [gcd(i,j)= 1]c_j ]

    [g_i=sum_{j=1} sum_{d|i,d|j} mu(d) c_j ]

    [g_i=sum_{d|i} mu(d) sum_{d|j} c_j ]

    然后发现后面的那一个式子(sum_{d|j} c_j)就是(d)的倍数出现次数,可以直接暴力(O(nln n))求出,预处理后(g_i)也可以暴力在(O(nln n))的时间内求出。

    接下来考虑(f)(f)直接算不好算,所以考虑反演,设(f^{'}_i)为集合的(gcd)(i)的倍数的出现次数,那么可以得到。

    [f^{'}_i=sum_{i|j} f_j ]

    然后发现这是一个狄利克雷后缀和的形式,至于如何反过来,可以简单地理解为反着写就没问题了,总时间复杂度(O(nln n))(这里偷换了(n)的概念,所有和时间复杂度有关的(n)都是值域大小)。

    代码:

    #include <cstdio>
    const int Maxn=500000;
    const int Maxm=10000000;
    const int Mod=1000000007;
    int pow_2[Maxn+5];
    bool np[Maxm+5];
    int p[Maxm+5],p_len;
    int mu[Maxm+5];
    void init(){
    	np[0]=np[1]=1;
    	mu[1]=1;
    	for(int i=2;i<=Maxm;i++){
    		if(!np[i]){
    			p[++p_len]=i;
    			mu[i]=-1;
    		}
    		for(int j=1,x;j<=p_len&&(x=i*p[j])<=Maxm;j++){
    			np[x]=1;
    			mu[x]=-mu[i];
    			if(i%p[j]==0){
    				mu[x]=0;
    				break;
    			}
    		}
    	}
    	pow_2[0]=1;
    	for(int i=1;i<=Maxn;i++){
    		pow_2[i]=(pow_2[i-1]<<1)%Mod;
    	}
    }
    int a[Maxm+5];
    int n;
    int g[Maxm+5],f[Maxm+5];
    int main(){
    	init();
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		int x;
    		scanf("%d",&x);
    		a[x]++;
    	}
    	for(int i=1;i<=p_len;i++){
    		for(int j=Maxm/p[i];j>0;j--){
    			a[j]+=a[j*p[i]];
    		}
    	}
    	for(int i=1;i<=Maxm;i++){
    		g[i]=a[i]*mu[i];
    	}
    	for(int i=1;i<=p_len;i++){
    		for(int j=1;j*p[i]<=Maxm;j++){
    			g[j*p[i]]+=g[j];
    		}
    	}
    	for(int i=1;i<=Maxm;i++){
    		f[i]=(pow_2[a[i]]-1+Mod)%Mod;
    	}
    	for(int i=p_len;i>0;i--){
    		for(int j=1;j*p[i]<=Maxm;j++){
    			f[j]=(f[j]-f[j*p[i]]+Mod)%Mod;
    		}
    	}
    	int ans=0;
    	for(int i=2;i<=Maxm;i++){
    		ans=(ans+1ll*f[i]*g[i])%Mod;
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    type( ) 和 isinstance( )
    el-input-number element计数器设置自定义小数位数
    Electron-Vue起步
    SmartGit破解使用的个人方法
    js 之 数组去重
    Vue动态class
    vue项目如何(友好的)刷新当前页
    Promise()与链式执行
    Vue过渡&循环切换&放大缩小动画
    css Margin塌陷问题(margin属性撑不开盒子)
  • 原文地址:https://www.cnblogs.com/withhope/p/13591105.html
Copyright © 2011-2022 走看看