数字构图

来源:互联网 发布:梦幻花园无法加载 网络 编辑:程序博客网 时间:2024/04/30 17:33

题目描述
小明用数字n和k构成了一个无向图,图中共n个点,编号从1到n,若gcd(i,j)>k,那么编号为i到编号为j的点就连上一条无向边。
现在,小明想要知道,在这个无向图中,编号为x的点和编号为y的点是否联通。

输入
第一行一个整数t,表示小明构造的图的数量(t<=5)
接下来t行,每行4个整数n,k,x,y(1<=x,y<=n),含义如题目描述。每个x和y只是针对同一行输入所在的图。

输出
输出t行,每行一个字符串,“Possible”表示该图中x和y联通;否则输出“Impossible”。

样例输入
2
12 2 8 9
12 2 11 12
样例输出
Possible
Impossible

提示
【样例1解释】
第一组样例:8->4->12->9 gcd(8,4)=4;gcd(4,12)=4;gcd(12,9)=3
第二组样例:11没有点和它相连

【数据范围】
对于20%的数据,n<=100
对于50%的数据,n<=2000
对于100%的数据,n<=1000000,0<=k<=n

Solution

无向边+判联通=并查集
一个很容易的想法就是枚举(k+1)-n的每个数,把相邻的倍数都连起来。
有个优化:如果你枚举了4,8 12 等4的倍数就不需要再枚举了,所以可以加个标记数组来优化。

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<cmath>#define ll long longusing namespace std;int n,m,x,y,z,f1,f2,cas;int vis[1000005],f[1000005];int get(int x){    if(f[x]==x) return x; else return f[x]=get(f[x]);}int main(){    cin>>cas;    while(cas--)     {        cin>>n>>m>>x>>y;        for(int i=1;i<=n;i++)         {            f[i]=i;            vis[i]=0;        }        for(int i=m+1;i<=n;i++)         if(vis[i]==0)         {            z=i;            while(z+i<=n)             {                vis[z]=1;                f1=get(z);                f2=get(z+i);                f[f2]=f1;                z+=i;            }        }        if(get(x)==get(y)) printf("Possible\n"); else printf("Impossible\n");    }    return 0;           }
0 0