题目:给出若干数,然后若干组询问,每次询问一个数,如果这个数存在,那么删去这个数,如果没有,添加这个数,每次询问后输出此时已经有的数中互质的有多少对。
思路:利用容斥原理求出已经有的数中与正在询问的数不互质的数的数目。先对所有数进行质数分解。然后通过含有的不同质数对所有数字进行分类。之后就可以用容斥原理统计数目。因为质数的数目实际上不大(每个数的质因子数目实际上很小)所以此类题可以直接用dfs。
PS:此题暴露出了在数学题上的若干细节问题,改了一上午。。。
#include<iostream> #include<map> #include<algorithm> #include<cstdio> #include<cstring> #include<cstdlib> #include<vector> #include<queue> #include<stack> #include<functional> #include<set> #define pb push_back using namespace std; typedef long long ll; typedef pair<ll,ll> P; const int maxv=5e5+400; vector<int> G[maxv]; vector<int> pri; bool p[maxv]; set<int> beer; int f[maxv],c[maxv],a[maxv]; int n,q; void init(){ for(int i=2;i<maxv;i++){ if(!p[i]) pri.pb(i); for(int j=0;j<pri.size()&&i*pri[j]<maxv;j++){ p[i*pri[j]]=1; if(i%pri[j]==0) break; } } } void getp(){ for(int i=0;i<n;i++){ int x=a[i]; int h=0; while(x>1&&pri[h]*pri[h]<=x){ if(x%pri[h]==0){ G[i].pb(pri[h]); while(x>1&&x%pri[h]==0) x/=pri[h]; } h++; } if(x!=1) G[i].pb(x); } } void read(){ cin>>n>>q; for(int i=0;i<n;i++) scanf("%d",a+i); } ll ans=0; int top=0; void dfs(int t,int x,int cont,int flag,int val){ if(t>=(int)G[x].size()){ if(cont==0) return; ans+=f[val]*flag; c[top++]=val; return; } dfs(t+1,x,cont,flag,val); dfs(t+1,x,cont+1,flag*-1,val*G[x][t]); } void solve(){ int x; while(q--){ scanf("%d",&x); x--; if(a[x]==1){ if(beer.find(x)!=beer.end()){ beer.erase(x); ans-=beer.size(); }else{ ans+=beer.size(); beer.insert(x); } }else{ if(beer.find(x)!=beer.end()){ beer.erase(x); ans-=beer.size(); top=0; dfs(0,x,0,-1,1); ans--; beer.erase(x); for(int i=0;i<top;i++) f[c[i]]--; }else{ top=0; ans+=beer.size(); dfs(0,x,0,1,1); beer.insert(x); for(int i=0;i<top;i++) f[c[i]]++; } } printf("%lld ",ans); } } int main(){ //freopen("/home/files/CppFiles/in","r",stdin); init(); read(); getp(); solve(); return 0; }