注意一堆數\(\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;
}