题解:P11867 大家的公因数 2
fish_love_cat · · 题解
没打比赛,赛后独立做出来的。
首先可以搞个桶上去。
然后跑线性筛,把每个质数视作一个点进行连边。
这样就建了图。
糊个并查集上去判掉不连通的情况。剩余问题离线出来,按照连通块排序。
容易发现一个限制能做当且仅当所在连通块能异或出指定数。
所以对于每个连通块的问题可以搞个线性基处理。
做完了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MB=60;
int a[500005],flc[10000005],fa[10000005],p[MB+5],d[MB+5],top,N;
bool aa[10000005],ans[500005],vis[10000005];
vector<int>ve[10000005];
struct fish{
int u,v,z;
int id;
int fa;
}Q[500005];
void ins(int x){
if(!x)return;
for(int i=MB;i>=0;i--)
if((1ll<<i)&x){
if(!p[i]){p[i]=x;break;}
else x^=p[i];
}
}
bool ask(int x){
for(int i=MB;i>=0;i--)
if((1ll<<i)&x)x^=p[i];
return x==0;
}
int find(int x){
return(x==fa[x]?x:fa[x]=find(fa[x]));
}
void zss(int n){
for(int i=2;i<=n;i++)
if(!aa[i]){
for(int j=1;j*i<=n;j++){
aa[j*i]=true;
if(flc[j*i]!=-1)
fa[find(j*i)]=find(i);
}
}
}
bool cmp(fish x,fish y){
return x.fa<y.fa;
}
void news(int x){
memset(p,0,sizeof p);
memset(d,0,sizeof d);
for(int i=0;i<ve[x].size();i++)ins(flc[ve[x][i]]);
}
signed main(){
int n,q;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i],N=max(N,a[i]);
for(int i=1;i<=N;i++)fa[i]=i,flc[i]=-1;
for(int i=1,x;i<=n;i++)cin>>x,flc[a[i]]=x;
zss(N);
cin>>q;
for(int i=1;i<=q;i++){
int u,v,z;
cin>>u>>v>>z;
if(find(u)!=find(v))continue;
Q[++top].u=u,Q[top].v=v,Q[top].z=z,Q[top].id=i,Q[top].fa=find(u);
vis[find(u)]=1;
}
sort(Q+1,Q+1+top,cmp);
for(int i=1;i<=N;i++)
if(vis[find(i)])ve[find(i)].push_back(i);
for(int i=1;i<=top;i++){
if(Q[i].fa!=Q[i-1].fa)news(Q[i].fa);
if(ask(Q[i].z))ans[Q[i].id]=1;
}
for(int i=1;i<=q;i++)puts((ans[i]?"Yes":"No"));
return 0;
}
本来写了 123 行,太难读了,于是现在只有 71 行。
效率比较低劣,跑了 40s 以上。
注意建图和并查集的一些细节。
提交记录。
建议评蓝或紫。