首页 > 代码库 > NOIp模拟赛 旅游

NOIp模拟赛 旅游

技术分享技术分享

 

 很神奇的一道题,金策大爷给的题解:

技术分享

 

什么叫神犇什么叫蒟蒻?

IOI冠军的一句基本相同让我思考了一下午。

 

看完了题解我就想都没想开始用遍历二分图搞,但是搞到了65分后就总是会WA掉7组。

然后仔细的看了看std,位运算上对几处做了常数上的优化,读起来异常麻烦,到最后看懂他在干什么了。但是总是不理解。

下午浪费了两节英语课思考原理,总之想明白了。

 

我简单说一下我的想法。

首先考虑如果一条路径的所有边权的gcd为$d$,那么不管正着走反着走或者绕上几圈,其总路径和一定为$kd$,$k$为任意正整数。

这一点学过gcd应该都很好想到。那么很显然的一件事就是如果一张图中两个相通的点,从一个点到另一个点的总路径和也一定为$kd$,$d$为这个连通分量里所有边权的gcd。同样的,如果需要把答案mod$K$,只需要$d=gcd(K,d)$即可,最后的答案一定是$d$或者0。这点转化是这道题的第一步。但不是最重要的一步。

 

这时候就把问题转化为了从$node_i$到$node_j$是否存在一条路径,使得其总长为$cK$,$c$为任意正整数。如果存在,显然答案为0,如果不存在,那么答案就是$d$。同时,需要提前用并查集判断连通性。

 

首先,考虑$K$为奇数的情况,在这种情况下,只要两点联通,答案一定为0,因为如果K为奇数,而假设从$node_i$到$node_j$的最短路径为$h$,那么一定存在一个数$b$使得$bh=cK$,如果想到了这点。就能拿到20分的部分分。

然后我们是否应该考虑$K$为偶数的情况?

 

并不,相对来说有更通用的情况。回到前面,我们已经得出了如果把总路径$modK$,那么一定存在一种方案使得从$node_i$到$node_j$的长度为$d$,这时候如果$K$为$d$的奇数倍,那么显然答案为0。

再思考,既然$d$为这个连通分量里所有边权的gcd,这也就意味着所有边的边权都是$d$的整数倍,也就是说所有边都可以拆成任意整数个边权为$d$的边。而如果存在一个数使得$hd==cK$,那么答案就是0。

那么是否可以把每个点拆为$node_i$和$node_{i+N}$,其中的两个点集之间相连的边的长度是奇数个$d$,而任意一个点集里的点之间的边都是偶数个$d$,这个显然可以用并查集维护。

这时候如果$node_i$和$node_j$位于一个点集,显然其是存在为0的答案。

 

但是除此之外,还存在特殊的情况。如果从一个点到另一个点既存在奇数个$d$的路径,也存在偶数个$d$的路径。怎么处理?

 

这时候只需要把这个联通块标记即可,这个连通块的任意两点之间到达的答案均为0。

 

技术分享
  1 //NOIp 0924 pod  2 //by Cydiater  3 //2016.9.24  4 #include <iostream>  5 #include <cstring>  6 #include <cstdlib>  7 #include <cstdio>  8 #include <queue>  9 #include <map> 10 #include <ctime> 11 #include <cmath> 12 #include <iomanip> 13 #include <algorithm> 14 #include <string> 15 using namespace std; 16 #define ll long long 17 #define up(i,j,n)        for(int i=j;i<=n;i++) 18 #define down(i,j,n)        for(int i=j;i>=n;i--) 19 #define FILE "pod" 20 const int MAXN=1e6+5; 21 const int oo=0x3f3f3f3f; 22 inline int read(){ 23     char ch=getchar();int x=0,f=1; 24     while(ch>9||ch<0){if(ch==-)f=-1;ch=getchar();} 25     while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();} 26     return x*f; 27 } 28 int N,M,Q,LINK[MAXN],len=0,f[MAXN],f2[MAXN],tol[MAXN]; 29 struct edge{ 30     int x,y,next,v; 31 }e[MAXN<<1]; 32 bool OK[MAXN]; 33 namespace solution{ 34     inline void insert(int x,int y,int v){e[++len].next=LINK[x];LINK[x]=len;e[len].y=y;e[len].v=v;e[len].x=x;} 35     int gcd(int a,int b){return b==0?a:gcd(b,a%b);} 36     int getf(int k){ 37         if(f[k]==k)        return k; 38         f[k]=getf(f[k]); 39         return f[k]; 40     } 41     int getf2(int k){ 42         if(f2[k]==k)        return k; 43         f2[k]=getf2(f2[k]); 44         return f2[k]; 45     } 46     void merge(int x,int y,int v){ 47         x=getf(x);y=getf(y); 48         if(tol[x]!=0)v=gcd(v,tol[x]); 49         if(tol[y]!=0)v=gcd(v,tol[y]); 50         tol[x]=v;f[y]=x; 51     } 52     int merge2(int x,int y,int v){ 53         if(v==1){ 54             if(getf2(x)==getf2(y))        return 0; 55             f2[getf2(x)]=getf2(y+N); 56             f2[getf2(y)]=getf2(x+N); 57         }else{ 58             if(getf2(x)==getf2(y+N))    return 0; 59             f2[getf2(x)]=getf2(y); 60             f2[getf2(x+N)]=getf2(y+N); 61         } 62         return 1; 63     } 64     void init(){ 65         N=read();M=read();Q=read(); 66         memset(tol,0,sizeof(tol)); 67         up(i,1,N){ 68             f[i]=i;f2[i]=i; 69             f2[i+N]=i+N; 70         } 71         up(i,1,M){ 72             int x=read(),y=read(),v=read(); 73             insert(x,y,v);insert(y,x,v); 74             merge(x,y,v); 75         } 76         up(i,1,M<<1){ 77             int x=e[i].x,y=e[i].y,v=e[i].v; 78             int d=tol[getf(e[i].x)]; 79             int flag=merge2(x,y,(v/d)%2); 80             if(!flag)OK[getf(x)]=1; 81             i+=1; 82         } 83     } 84     void slove(){ 85         while(Q--){ 86             int x=read(),y=read(),K=read(); 87             if(getf(x)!=getf(y))        puts("NIE");//unconnect 88             else{ 89                 int d=gcd(K,tol[getf(x)]); 90                 if((K/d)&1)                            puts("0"); 91                 else{ 92                     if(OK[getf(x)])                    puts("0"); 93                     else{ 94                         if(getf2(x)==getf2(y))        puts("0");//same color 95                         else                          printf("%d\n",d); 96                     } 97                 } 98             } 99         }100     }101 }102 int main(){103     freopen(FILE".in","r",stdin);104     freopen(FILE".out","w",stdout);105     using namespace solution;106     init();107     slove();108     return 0;109 }
View Code

 

NOIp模拟赛 旅游