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 }

时间: 2024-12-17 00:07:07

NOIp模拟赛 旅游的相关文章

【简单思考】noip模拟赛 NTR酋长

NTR酋长 (ntr.pas/.c/.cpp) 黄巨大终于如愿以偿的进入了czy的后宫中……但是czy很生气……他要在黄巨大走到他面前的必经之路上放上几个NTR酋长来阻挡黄巨大. 众所周知,NTR酋长有一个技能是沟壑(F).它会在地图上产生一条长长的障碍物阻挡人前进.Czy打算在一个n*m的矩形(必经之路?)中放上NTR酋长.NTR酋长要一个一个放下去,而且每放一个都会向四角倾斜的方向放出无限长的沟壑,而已经被沟壑挡住的地方就不能再放NTR酋长了. 请注意:不会出现沟壑的路径挡住另一个沟壑的情况

【noip模拟赛】 射击

这题似乎是什么安阳一中的模拟题,不管了,反正是学长出的noip模拟赛里面的题目.... 射击(shoot.pas/.c/.cpp) 时间限制:1s,内存限制128MB 题目描述: 据史书记载,对越反击战时期,有位中国侦察兵,他的代号叫814.一天他执行狙击任务,他的任务地区是n座恰巧在一条直线上的山.这些山所在直线恰巧为东西走向,山从东到西依次编号为1~n.一天814隐藏在编号为k的山上,每座山上都有1个目标. 814也非常的厉害,任务结束时杀了很多人,可是史书中只记载了两点: 1:814一定攻

NOIP模拟赛

#1[Nescafé 31]杯NOIP模拟赛 t1 题意:n*m的棋盘上从(1,1)走到(n,m),只能向下或向右,一些格子有老鼠,每个老鼠互不相同,当处于与老鼠有重边的格子时,视为看见了这只老鼠,求到终点看到最少的不同老鼠数. 分析:DP 由于求得是看到的不同的老鼠数目,不能直接用过河卒做,因为同一个位置的老鼠可能会统计多次,我们还需要增加一维即方向. f[i,j,0]表示到从上面一个格子走到(i,j)时最少老鼠数,f[i,j,1]表示左边. f[i,j,0]:=min(f[i-1,j,0]+

NOIP模拟赛 6.29

2017-6-29 NOIP模拟赛 Problem 1 机器人(robot.cpp/c/pas) [题目描述] 早苗入手了最新的Gundam模型.最新款自然有着与以往不同的功能,那就是它能够自动行走,厉害吧. 早苗的新模型可以按照输入的命令进行移动,命令包括‘E’.‘S’.‘W’.‘N’四种,分别对应东南西北.执行某个命令时,它会向对应方向移动一个单位.作为新型机器人,它可以执行命令串.对于输入的命令串,每一秒它会按命令行动一次.执行完命令串的最后一个命令后,会自动从头开始循环.在0时刻时机器人

2012-10-20 NOIP模拟赛

      2012-10-20 NOIP模拟赛 by coolyangzc 共3道题目,时间3小时 题目名 高级打字机 不等数列 经营与开发 源文件 type.cpp/c/pas num.cpp/c/pas exploit.cpp/c/pas 输入文件 type.in num.in exploit.in 输出文件 type.out num.out exploit.out 时间限制 1000MS 1000MS 1000MS 内存限制 256MB 256MB 256MB 测试点 5+(5) 10

2017 9 11 noip模拟赛T2

#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=205; int map[N][N]; int d[N],tag[N],book[N],f[N]; int n,m; void work(int x) { memset(d,63,sizeof(d)); memset(book,0,sizeof(book)); memset(f,0,sizeof(

【noip模拟赛4】Matrix67的派对 暴力dfs

[noip模拟赛4]Matrix67的派对 描述 Matrix67发现身高接近的人似乎更合得来.Matrix67举办的派对共有N(1<=N<=10)个人参加,Matrix67需要把他们安排在圆桌上.Matrix67的安排原则是,圆桌上任意两个相邻人的身高之差不能超过K.请告诉Matrix67他共有多少种安排方法. 输入 第一行输入两个用空格隔开的数N和K,其中1<=N<=10,1<=K<=1 000 000. 第二行到第N+1行每行输入一个人的身高值.所有人的身高都是不

2014-11-3 NOIP模拟赛2

NOIP 2014 水题模拟赛 (请选手务必仔细阅读本页内容) 一.题目概况 中文题目名称 数列 刷漆 排队 英文题目与子目录名 seq paint layout 可执行文件名 seq paint layout 输入文件名 seq.in paint.in layout.in 输出文件名 seq.out paint.out layout.out 每个测试点时限 2 秒 1 秒 1 秒 测试点数目 10 10 10 每个测试点分值 10 10 10 附加样例文件 无 无 无 结果比较方式 全文比较(

2014-9-9 NOIP模拟赛

东方幻想乡系列模拟赛Stage 1命题 Nettle审题 Barty ccy1991911 FlanS39 Wagner T2 高精除高精,从来没写过,不知道怎么写,我就用大数减小数ans次,果断超时. T4 Tarjan的板子题,好久没写,中间出现了一些小错误 ①是尽管有双向边,Tarjan函数中也不必排除双向边 ②Tarjan算法有时候不能一步完成,需要做最多n次,用循环解决 ③问题是关于这个题目的虽然输入n代表有n个点,但是下面的连边中有些点根本没出现过,所以设一个数组记录有效点. Pro