#24. 【IOI2014】Rail
台湾有一个连接着岛的东、西两岸的庞大的铁路线。这个铁路线包含有 mm 个区段。这些相连的区段以数字 0,…,m−10,…,m−1 为编号,且编号由西端开始。每一个区段都包含一段在北面向西单行的路轨,以及一段在南面向东单行的路轨。部分区段还可能会有一个位于这两段路轨之间的车站。
区段可以分成三种类型。其中 C 类型的区段会有一个车站,而且只能从北面的路轨进入车站并且从南面的路轨离开。D 类型的区段也会有一个车站,而且只能从南面的路轨进入车站并且从北面的路轨离开。空 类型的区段则没有车站。举例来说,如下图所示,区段 00、44 和 66 是空类型区段,区段 11、22 和 33 是C类型,而区段 55 则是D类型。这些区段沿水平方向连接在一起。相邻区段的路轨之间以连接器彼此相连,在图中所示的灰色方块就是连接器。
在这个铁路系统中共有 nn 个车站,它们分别以数字 00 到 n−1n−1 为编号。这里假设我们可以由任何一个车站出发、沿着路轨的方向到达任何其他车站。例如我们可以由车站 00 到达车站 22,所经路线是由区段 22 开始,经区段 33 及区段 44 的南面路轨,然后经由区段 55 通过车站 11,再经区段 44 的北面路轨,最后到达区段 33 并由北面路轨进入车站 22。
由于从一个车站到另一个车站有多个不同的可行路线,我们定义由一个车站到另一个车站的距离为所有可行路线中所经的连接器的最少数量。例如由车站 00 到车站 22 的最短路线所经的区段是 2→3→4→5→4→32→3→4→5→4→3,所经的连接器数目为 55,因此距离为 55。
该铁路系统是由计算机系统管理的。不幸的是,在一次电力事故后,计算机系统丢失了各车站所在的区段编号及其相应的类型。目前仅知道车站 00 所在的区段编号,且该区段总是 C 类型。幸运的是计算机能够查询出任意两个车站之间的距离。例如计算机可以查询“车站 00 与车站 22 的距离”,并且得到答案为 55。
任务
你需要编写一个函数 findLocation,以确定每一个车站所在的区段编号及其相应的类型。
- findLocation(n, first, location, stype)
- n: 车站的数目
- first: 车站 00 所在区段的编号。
- location: 大小为 nn 的数组; 你需要将车站 ii 所在的区段编号存放到 location[i] 中。
- stype: 大小为 nn 的数组;你需要将车站 ii 的类型存放到 stype[i] 中:其中 1 表示 C 类型,而 2 则表示 D 类型。
你可以调用一个函数 getDistance 以帮助你找出各车站的所在区段及其类型。
- getDistance(i, j) 将返回车站 ii 到车站 jj 的距离。如果调用 getDistance(i, i) 将返回00。如果 ii 或 jj 在 0≤i,j≤n−10≤i,j≤n−1 范围之外,getDistance(i, j) 将返回 −1−1。
子任务
在所有的子任务中,区段的数目 mm 不会超过 10000001000000。在部分子任务中,调用 getDistance 的次数是受限的,且该限制将因子任务而异。如果调用次数超过相应限制,你的程序将被判为“wrong answer”。
子任务 | 分值 | nn | getDistance的调用次数 | 备注 |
---|---|---|---|---|
1 | 8 | 1≤n≤1001≤n≤100 | 无限制 | 除车站 00 外,其他车站均在 D 类型区段中。 |
2 | 22 | 1≤n≤1001≤n≤100 | 无限制 | 所有在车站 00 东侧的车站均在 D 类型区段中, 而所有在车站 00 西侧的车站均在 C 类型区段中。 |
3 | 26 | 1≤n≤50001≤n≤5000 | n(n−1)/2n(n−1)/2 | 无其他限定 |
4 | 44 | 1≤n≤50001≤n≤5000 | 3(n−1)3(n−1) | 无其他限定 |
实现细节
本题只支持 C/C++。
你只能提交一个源文件实现如上所述的 findLocation 函数,并且遵循下面的命名和接口。你需要包含头文件 rail.h。
void findLocation(int n, int first, int location[], int stype[]);
函数getDistance的接口信息如下。
int getDistance(int i, int j);
评测方式
评测系统将读入如下格式的输入数据:
- 第 11 行: 子任务编号
- 第 22 行: nn
- 第 3+i3+i 行,(0≤i≤n−1)(0≤i≤n−1):stype[i](1表示C类型,2表示D类型), location[i]。
在 findLocation 返回后,如果你的程序计算出的 location[0] …… location[n-1] 和 stype[0] …… stype[n-1] 与输入数据一致,评测系统将输出 CorrectCorrect,否则输出 IncorrectIncorrect。
时间限制:3s3s
空间限制:256MB256MB
下载
分析:
虽然说知道自己菜,但是好不容易有道题在uoj上rank1,怎么能不发篇题解纪念一下。
![](https://i-blog.csdnimg.cn/blog_migrate/3f009fff12e241b5d78edd9b396c0c71.png)
如果其为D形车站那么,C的位置为location[A] - Dis[C],B的位置为location[A] - Dis[B] = location[C] + D,D为d(C,B)
通过推导 D = (Dis[C] + tmp - Dis[i] ) / 2,这个画图或者公式推都行。
然后就判断一下 location[C] + D,有没有一个C形车站(即B)就可以,判断有没有C形车站hash就行。
如果满足且location[C] + D < frist ,那么i为D形车站,位置为lcation[C] + tmp
如果不满足或者location[C]+ D >=first,那么i为C形车站,位置为location[A] - Dis[i]
在A右边讨论同理
AC代码:
# include "rail.h" # include <iostream> # include <cstring> # include <algorithm> using namespace std; const int N = 5e3 + 12; const int mod = 2e5 + 12; struct node{ int dis,id; bool operator <(const node & other)const{return dis < other.dis;} }l[N],r[N]; int dis[N],Dis[N],t1,t2,Amx = 1e9,A,que[N],tmp,d,t,hs[mod]; void add(int p) { int x = p % mod; while(hs[x] != -1) { x++; if(x == mod)x = 0; } hs[x] = p; } bool find(int p) { int x = p % mod; if(x < 0)return false; while(hs[x] != -1) { if(hs[x] == p)return true; x++; if(x == mod)x = 0; } return false; } void findLocation(int n, int first, int location[], int stype[]) { memset(hs,-1,sizeof hs); location[0] = first;stype[0] = 1; if(n == 1)return; for(int i = 1;i < n;i++)dis[i] = getDistance(0,i),A = dis[i] < Amx ? i : A,Amx = dis[i] < Amx ? dis[i] : Amx; for(int i = 1;i < n;i++)if(i != A)Dis[i] = getDistance(A,i); location[A] = first + dis[A];stype[A] = 2; for(int i = 0;i < n;i++) { if(i == 0 || i == A)continue; if(dis[A] + Dis[i] == dis[i] && Dis[i] < dis[A])location[i] = location[A] - Dis[i],stype[i] = 1; if(dis[A] + Dis[i] == dis[i] && Dis[i] > dis[A])l[++t1] = (node){Dis[i],i}; if(dis[A] + Dis[i] != dis[i])r[++t2] = (node){dis[i],i}; } sort(l + 1,l + t1 + 1);sort(r + 1,r + t2 + 1); if(t2) { location[que[t = 1] = r[1].id] = first + r[1].dis;stype[r[1].id] = 2;add(location[r[1].id]); for(int i = 2;i <= t2;i++) { tmp = getDistance(r[i].id,que[t]); d = (dis[que[t]] + tmp - dis[r[i].id]) / 2; if(location[que[t]] - d > location[A] && find(location[que[t]] - d)) location[r[i].id] = location[que[t]] - tmp,stype[r[i].id] = 1; else location[r[i].id] = first + r[i].dis,stype[r[i].id] = 2,add(location[r[i].id]),que[++t] = r[i].id; } } if(t1) { location[que[t = 1] = l[1].id] = location[A] - l[1].dis;stype[l[1].id] = 1;add(location[l[1].id]); for(int i = 2;i <= t1;i++) { tmp = getDistance(l[i].id,que[t]); d = (Dis[que[t]] + tmp - Dis[l[i].id]) / 2; if(location[que[t]] + d < first && find(location[que[t]] + d)) location[l[i].id] = location[que[t]] + tmp,stype[l[i].id] = 2; else location[l[i].id] = location[A] - l[i].dis,stype[l[i].id] = 1,add(location[l[i].id]),que[++t] = l[i].id; } } }