动态维护,每次只考虑有多少个数和a[x]互质。容斥原理
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <queue>
#define foreach(it,v) for(__typeof(v.begin()) it = v.begin(); it != v.end(); ++it)
using namespace std;
typedef long long ll;
const int maxn = 5e5 + 5;
bool check[maxn];
vector<int> v[maxn];
int g[maxn],a[maxn];
void init(int n)
{
memset(check, 0, sizeof check);
for(int i = 2; i <= n; i++) {
if(check[i])continue;
for(int j = i; j <= n; j += i)
v[j].push_back(i),check[j] = 1;
}
}
int Query(int x)
{
vector<int> &cur = v[x];
int M,sz = cur.size();
M = 1<<sz;
int ans = 0;
for(int s = 0; s < M; s++) {
int now = 1,tot = 0;
for(int j = 0; j < sz; j++)if((s>>j)&1){
now *= cur[j];
tot++;
}
if(tot & 1) ans -= g[now];
else ans += g[now];
}
return ans;
}
void Modify(int x,int d)
{
vector<int> &cur = v[x];
int M,sz = cur.size();
M = 1<<sz;
for(int s = 0; s < M; s++) {
int now = 1;
for(int j = 0; j < sz; j++)if((s>>j)&1){
now *= cur[j];
}
g[now] += d;
}
}
int main(int argc, char const *argv[])
{
init(maxn-5);
int n,q;
while(~scanf("%d%d",&n,&q)) {
memset(check,0,sizeof (check[0])*(n+2));
memset(g,0,sizeof g);
for(int i = 1; i <= n; i++) {
scanf("%d",a + i);
}
ll ans = 0;
while(q--) {
int x;scanf("%d",&x);
if(!check[x]) {
check[x] = 1;
ans += Query(a[x]);
Modify(a[x],1);
}else {
check[x] = 0;
Modify(a[x],-1);
ans -= Query(a[x]);
}
printf("%I64d\n", ans);
}
}
return 0;
}