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)\neq 1\)就可以加入答案.考慮優化枚舉\(x\),對於一個\(i\)\(\gcd(x,i)\neq1\)\(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\n",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章