51Nod 1439:互质对(用莫比乌斯来容斥)
有n个数字,a11,a22,…,ann。有一个集合,刚开始集合为空。然后有一种操作每次向集合中加入一个数字或者删除一个数字。每次操作给出一个下标x(1 ≤ x ≤ n),如果axx已经在集合中,那么就删除axx,否则就加入axx。
问每次操作之后集合中互质的数字有多少对。
注意,集合中可以有重复的数字,两个数字不同当且仅当他们的下标不同。
比如a11=a22=1。那么经过两次操作1,2之后,集合之后存在两个1,里面有一对互质。
Input单组测试数据。
第一行包含两个整数n 和 q (1 ≤ n, q ≤ 2 × 10^5)。表示数字的种类和查询数目。
第二行有n个以空格分开的整数a11,a22,…,ann (1 ≤ aii ≤ 5 × 10^5),分别表示n个数字。
接下来q行,每行一个整数x(1 ≤ x ≤ n),表示每次操作的下标。Output对于每一个查询,输出当前集合中互质的数字有多少对。Sample Input
样例输入1 5 6 1 2 3 4 6 1 2 3 4 5 1 样例输入2 2 3 1 1 1 2 1
Sample Output
样例输出1 0 1 3 5 6 2 样例输出2 0 1 0
题意:给定一个数组,现在全部数都没有填进对于的位置上去。现在,有一些操作,或是把a[i]填到i位置,或是把a[i]从i位置取出来。问当前填进去的数列有多少个互质对。
思路:显然可以用容斥定理来做。怎么破? 对于当前的集合(大小为N),我加一个x进去,会增加多少互质对呢?答案是N-与x不互质的个数。
对于x的所有约数去重,比如N=5;x=24。add=N-有约数2的个数-有约数3个个数+有约数4的个数+有约数6的个数+0*有约数12的个数+0*有约数24的个数。
对于它前面的符号,取决于约数的素因子factor:
如果factor为1,它就是1;
如果factor有平方因子,符号为0; 如12=2*2*3
如果factor有奇数个素数,符号为-1; 如2
如果factor有偶数个素数,符号为1;如6
所以,我们先用筛法得到每个数的约数(O(NlgN));
然后加一个数x,用上面的方法,求出多了多少个素数对。我们就对x的所有约数++;
反之亦然;
(不加输出优化会TLE
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=500000; int p[maxn+10],cnt; short int vis[maxn+10],mu[maxn+10]; void read(int &x){ //输入 x=0; char c=getchar(); while(c>'9'||c<'0') c=getchar(); while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar(); } void Put(ll x) //输出 { if(x>9) Put(x/10); putchar(x%10+'0'); } void prime() //筛莫比乌斯数 { mu[1]=1; for(int i=2;i<=maxn;i++){ if(!vis[i]) p[++cnt]=i,mu[i]=-1; for(int j=1;j<=maxn&&i*p[j]<=maxn;j++){ vis[i*p[j]]=1; mu[i*p[j]]=-mu[i]; if(i%p[j]==0) { mu[i*p[j]]=0; break; } } } } int a[200010],num[maxn+10];ll ans; vector<int>G[maxn+10]; int main() { prime(); int N,Q,x,i,j,Max=0; scanf("%d%d",&N,&Q); for(i=1;i<=N;i++) read(a[i]),Max=max(Max,a[i]),vis[i]=0; for(i=1;i<=Max;i++){ //筛约数 for(j=i;j<=Max;j+=i) G[j].push_back(i); } while(Q--){ read(x); int L=G[a[x]].size(); if(vis[x]==1){ for(i=0;i<L;i++) num[G[a[x]][i]]--; for(i=0;i<L;i++) ans-=mu[G[a[x]][i]]*num[G[a[x]][i]]; } else { for(i=0;i<L;i++) ans+=mu[G[a[x]][i]]*num[G[a[x]][i]]; for(i=0;i<L;i++) num[G[a[x]][i]]++; } vis[x]=vis[x]^1; Put(ans); puts(""); } return 0; }