分析

给出 \(n\) 个数,每次向集合增加或去掉其中一个数,求集合内有多少无序数对互质。

考虑计算每一次操作对答案的影响,在总个数的基础上,减去与其不互质的个数,就是与其互质的个数,但如果枚举因数直接相减,显然会减重,所以考虑容斥。

比如你你用 \(cnt_i\) 表示以 \(i\) 为因数的数有多少个,减了 \(cnt_2\),减了 \(cnt_3\),你就应该把 \(cnt_6\) 加回来。你这样列举,你就会发现,一个质因数就减,两个就加,如果有重复的多个质因数不需要管,这样就显然是 \(\mu\) 函数了。

所以对每一个因数,贡献就是 \(cnt_a*\)\(mu_a\)。将贡献累加,要删的时候减,要加的时候加就行了。

代码

#include<bits/stdc++.h>
using namespace std;
inline void read(int &res){
	res=0;
	int f=1;
	char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9')res=(res<<1)+(res<<3)+c-48,c=getchar();
	res*=f;
}
int n,m;
int cj[500005];
int cnt[500005];
vector<int>v[200005];
inline void sol(int x,int y){//找出所有因数 
	for(int i=1;i*i<=x;i++){
		if(x%i==0){
			v[y].push_back(i);
			if(i*i!=x)v[y].push_back(x/i);
		}
	}
}
int is[500005];
bool vis[200005];
int tot;
int pri[500005],cnt_p;
void init(){
	cj[1]=1;
	for(int i=2;i<=500000;i++){
		if(!is[i]){
			cj[i]=-1;//莫比乌斯函数 
			pri[++cnt_p]=i;
		}
		for(int j=1;j<=cnt_p&&pri[j]*i<=500000;j++){
			if(i%pri[j]==0){
				is[i*pri[j]]=1;
				continue;
			}
			cj[i*pri[j]]=cj[i]*(-1);
			is[i*pri[j]]=1;
		}
	}
}
long long ans;
inline int query(int x){
	int sum=0;
	for(int i=0;i<v[x].size();i++){
		int a=v[x][i];
		sum+=cj[a]*cnt[a];//累加贡献 
	}
	return sum;
}
inline void work(int x,int bo){
	if(bo){//加上 
		tot++;
		vis[x]=1;
		for(int i=0;i<v[x].size();i++){
			int a=v[x][i];
			cnt[a]++;
		}
	}
	else {//去掉 
		tot--;
		vis[x]=0;
		for(int i=0;i<v[x].size();i++){
			int a=v[x][i];
			cnt[a]--;
		}
	}
}
int tp[200005];
signed main()
{
	read(n);read(m);
	init();
	for(int i=1;i<=n;i++){
		int x;
		read(x);
		sol(x,i);
		if(x==1)tp[i]=1;
	}
	for(int i=1;i<=m;i++){
		int x;
		read(x);
		int k=query(x);
		if(tp[x]&&vis[x])k--;//1会和自己互质 
		if(vis[x])work(x,0),ans-=k;
		else work(x,1),ans+=k;
		printf("%lld\n",ans);
	}
	return 0;
}
/*
5 5
2 4 6 8 10
1 2 3 4 5

*/
posted on 2021-09-23 21:57  漠寒·  阅读(37)  评论(0编辑  收藏  举报