Codeforces 585E - Present for Vitalik the Philatelist(简单莫反+狄利克雷前缀和)
首先我们注意到对于固定的 \(x\) 及集合 \(S\),如果 \(\gcd(S)>1,\gcd(x,\gcd(S))=1\) 那么必然有 \(x\notin S\),否则显然有 \(\gcd(S)=\gcd(x,\gcd(S))\) 可立即推出矛盾,也就是说我们可以直接忽略这个条件。我们考虑直接枚举 \(\gcd(S)=x\),设 \(f_x\) 表示 \(\gcd(S)=x\) 的集合 \(S\),\(g_x\) 表示 \(a_{1...n}\) 中有多少个数与 \(x\) 互质,那么这种情况对答案的贡献显然为 \(f_xg_x\),累加一下即可,即 \(ans=\sum\limits_{x>1}f_xg_x\)
接下来考虑怎样求 \(f_x,g_x\),首先是 \(f_x\),按照套路我们设 \(c_x\) 为可重集中 \(x\) 出现了多少次,这样我们可以枚举值 instead of 下标,即 \(f_x=\sum\limits_{y}[\gcd(x,y)=1]c_y\),我们按照套路进行莫反:
接下来考虑 \(g_x\),首先直接求是不容易的,不过按照套路我们设 \(h_x=\sum\limits_{x\mid y}g_y\),即 \(x\mid\gcd(S)\) 的集合 \(S\) 个数。那么关于,显然所有是 \(x\) 的倍数的数都可以被加入进 \(S\) 中,如果我们设 \(t_x\) 表示可重集中有多少个数是 \(x\) 的倍数,那么显然有 \(h_x=2^{t_x}\)。而显然 \(t_x=\sum\limits_{x\mid y}c_y\),故上面 \(f_x\) 的式子又可以改写为 \(f_x=\sum\limits_{d\mid x}\mu(d)t_d\)
因此接下来我们只用实现三个操作:
- 已知 \(c_x\) 求 \(t_x=\sum\limits_{x\mid y}c_y\)
- 已知 \(\mu(d)t_d\) 求 \(f_x=\sum\limits_{d\mid x}\mu(d)t_d\)
- 根据 \(h_x\) 即 \(h_x=\sum\limits_{x\mid y}g_y\) 反解出 \(g_x\)
不难发现这三个操作实际上是等价的,都可以写成类似于给定序列 \(a\) 求序列 \(b\) 满足 \(b_i=\sum\limits_{j\mid i}a_j\) 的形式。考虑什么样的 \(i,j\) 满足 \(a_i\) 会对 \(b_j\) 产生贡献,我们将 \(i,j\) 分解质因数,那么对于质因子 \(p\),如果 \(i\) 的质因数分解式中 \(p\) 的次数为 \(\alpha\),\(j\) 的质因数分解式中 \(p\) 的次数为 \(\beta\) 那么必须有 \(\alpha\ge\beta\),因此可以将这玩意儿看作一个 \(\pi(n)\) 维的高维前缀和,按照高维前缀和的套路跑一下即可,时间复杂度 \(n\log\log n\),据说这玩意儿有个专门的名字叫 dirichlet 狄利克雷前缀和?
const int MAXN=5e5;
const int MAXM=1e7;
const int MOD=1e9+7;
int n,pw[MAXN+5],c[MAXM+5],f[MAXM+5],g[MAXM+5];
int pr[MAXM/10+5],pcnt=0,mu[MAXM+5];
bitset<MAXM+5> vis;
void sieve(int n){
mu[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i]){pr[++pcnt]=i;mu[i]=-1;}
for(int j=1;j<=pcnt&&pr[j]*i<=n;j++){
vis[pr[j]*i]=1;
if(i%pr[j]==0) break;
else mu[i*pr[j]]=-mu[i];
}
}
}
int main(){
scanf("%d",&n);pw[0]=1;sieve(MAXM);
for(int i=1;i<=n;i++) pw[i]=pw[i-1]*2%MOD;
for(int i=1,x;i<=n;i++) scanf("%d",&x),c[x]++;
for(int i=1;i<=pcnt;i++) for(int j=MAXM/pr[i];j;j--) c[j]+=c[j*pr[i]];
for(int i=1;i<=MAXM;i++) f[i]=pw[c[i]]-1,g[i]=c[i]*mu[i];
for(int i=1;i<=pcnt;i++) for(int j=1;j*pr[i]<=MAXM;j++) g[j*pr[i]]+=g[j];
for(int i=1;i<=pcnt;i++) for(int j=1;j*pr[i]<=MAXM;j++) f[j]=(f[j]-f[j*pr[i]]+MOD)%MOD;
int ans=0;for(int i=2;i<=MAXM;i++) ans=(ans+1ll*g[i]*f[i])%MOD;
printf("%d\n",ans);
return 0;
}

浙公网安备 33010602011771号