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