[Codeforces 547C] Mike And Foam 莫比乌斯反演
F(i)=sigma(i|d,f(d))=C(g(i),2),g(i)是现在的i的倍数的数量,f(i)=sigma(i|d,miu(d/i)*F(d))所求即为f(1)的值.动态维护g(i)即可.
Code:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll ans=0;
int n,q,id;
int miu[500005],pri[100005],cnt=0;
bool isp[500005];
bool vis[200005];
int a[200005];
ll g[500005];
inline void gmiu()
{miu[1]=1;
for (int i=2;i<=500000;i++)
{if (!isp[i]) {pri[++cnt]=i;miu[i]=-1;}
for (int j=1;j<=cnt&&pri[j]*i<=500000;j++)
{isp[i*pri[j]]=1;
if (i%pri[j]==0) {miu[i*pri[j]]=0;break;}
miu[i*pri[j]]=miu[i]*(-1);
}
}
}
void add(int num,int del)
{int i,t;
ll prv,rev;
for (i=1;i*i<=num;i++)
{if (num%i==0)
{t=i;prv=miu[t]*g[t]*(g[t]-1)/2;
g[t]+=del;rev=miu[t]*g[t]*(g[t]-1)/2;
ans-=prv;ans+=rev;
if (i!=num/i)
{t=num/i;prv=miu[t]*g[t]*(g[t]-1)/2;
g[t]+=del;rev=miu[t]*g[t]*(g[t]-1)/2;
ans-=prv;ans+=rev;
}
}
}
printf ("%lld\n",ans);
}
int main (){
gmiu();
int i;
scanf ("%d%d",&n,&q);
for (i=1;i<=n;i++)
{scanf ("%d",&a[i]);}
for (i=1;i<=q;i++)
{scanf ("%d",&id);
if (!vis[id]) {vis[id]=1;add(a[id],1);}
else {vis[id]=0;add(a[id],-1);}
}
return 0;
}