• CF585E Present for Vitalik the Philatelist


    cf

    注意一堆数(gcd)的贡献可以改为一堆数公因数的贡献,但是只取最大的

    所以我们先对于每个数,把每个出现次数(>1)的质因子给除成只有一次,也就是把每个数改成他所有不同质因子的积方便统计答案.然后设(h_i)(i)是这(n)个数里面多少个数的因数,这个可以初始先对每个(i)(h_{a_i})加一,然后(以质因子出现次数为维度)高维后缀和求出.这时候再设(g_i=2^{h_i}-1)表示集合所有数的(gcd)(i)倍数的集合数,以及(f_i)为表示集合所有数的(gcd)(i)的集合数,可以发现(g)(f)的后缀和形式,所以可以高维后缀差分求出(f)

    现在枚举数(x)和表示集合所有数(gcd)(i),满足(gcd(x,i) eq 1)就可以加入答案.考虑优化枚举(x),对于一个(i)(gcd(x,i) eq1)(x)个数.如果我们用(h)来统计,对于一个(i),假设某个(x)和他的(gcd)(y(y>1)),那么(y)的因数处也会有来自(x)的贡献,但是我们只能统计(x)(y)的贡献,所以考虑容斥,一项一项推可以发现(y)项系数为(-mu(y)),所以给所有(h_y)乘上对应(-mu(y))后,高维前缀和即可得到要求的贡献数组

    #include<bits/stdc++.h>
    #define LL long long
    #define db double
    
    using namespace std;
    const int N=1e7+10,M=5e5+10,mod=1e9+7;
    int rd()
    {
        int x=0,w=1;char ch=0;
        while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
        return x*w;
    }
    void ad(int &x,int y){x+=y,x-=x>=mod?mod:0;}
    int n,pw[M],a[M],pp[N],prm[N/10],tt,f[N],g[N],nt[N],hd,tl,vs[N],ti;
    bool v[N];
    void cal(int *f,int fx,int d)
    {
        for(int i=1;i<=tt;++i)
        {
    	    int x=prm[i],lm=tl/x;
    	    ++ti;
        	for(int j=hd,k;j<=lm;j=nt[j+1])
        	{
        	    if(vs[j]==ti) continue;
        	    k=j*x,vs[k]=ti;
        	    if(fx) ad(f[j],(~d)?f[k]:mod-f[k]);
        	    else ad(f[k],(~d)?f[j]:mod-f[j]);
        	}
        }
    }
    
    int main()
    {
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
        hd=1,tl=1,nt[1]=pp[1]=1;
        for(int i=2;i<=N-5;++i)
        {
        	if(!pp[i]) pp[i]=i,prm[++tt]=i;
        	for(int j=1;i*prm[j]<=N-5;++j)
        	{
        	    pp[i*prm[j]]=prm[j],v[i*prm[j]]|=v[i];
        	    if(i%prm[j]==0) {v[i*prm[j]]=1;break;}
        	}
        	if(!v[i])
        	{
        	    nt[i]=i;
        	    for(int j=tl+1;j<i;++j) nt[j]=i;
        	    tl=i;
        	}
        }
        nt[tl+1]=tl+2;
        n=rd(),pw[0]=1;
        for(int i=1;i<=n;++i) pw[i]=(pw[i-1]<<1)%mod;
        for(int i=0;i<=n;++i) ad(pw[i],mod-1);
        for(int i=1;i<=n;++i)
        {
        	a[i]=rd();
        	int ls=1,sx=1,x=a[i];
        	while(x>1)
        	{
        	    int np=pp[x];
        	    if(np!=ls) sx*=np;
        	    x/=np,ls=np;
        	}
        	a[i]=sx,++f[a[i]];
        }
        cal(f,1,1);
        g[1]=-1;
        for(int i=hd;i<=tl;i=nt[i+1]) g[i]=g[i/pp[i]]+1;
        for(int i=hd;i<=tl;i=nt[i+1])
    	g[i]=((g[i]&1)?f[i]:mod-f[i])%mod,f[i]=pw[f[i]];
        cal(f,1,-1),f[1]=0;
        g[1]=0,cal(g,0,1);
        int ans=0;
        for(int i=hd+1;i<=tl;i=nt[i+1]) ad(ans,1ll*f[i]*(n-g[i])%mod);
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    怎样改动、扩展并重写Magento代码
    解决Gradle minifyEnabled无法找到错误
    使用Hadoop的MapReduce与HDFS处理数据
    cmake 学习笔记(一)
    简单的日志系统
    WebStorm 7.0 注冊码
    DOS命令大全--具体解释
    SQL SERVER之数据查询
    闰年的定义
    Javascript作用域链
  • 原文地址:https://www.cnblogs.com/smyjr/p/12585089.html
Copyright © 2020-2023  润新知