#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。

  1. void findLocation(int n, int first, int location[], int stype[]);

函数getDistance的接口信息如下。

  1. int getDistance(int i, int j);

评测方式


评测系统将读入如下格式的输入数据:

  1. 第 11 行: 子任务编号
  2. 第 22 行: nn
  3. 第 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,怎么能不发篇题解纪念一下。

题意很简单,套路也很明显,首先看到询问次数是3(n - 1),这种一般是O(n - 1)用第0点找到最远/近点,然后用最远/近点再O(n - 1)扫一遍,最后再利用两次询问和第三次某种特殊查询得出答案。
这道题先O(n - 1)找出最近点,一定是距离0最近的在右边的D形车站记为A,记录d(0 ->i)距离为dis[i]
然后O(n - 2)用A扫一遍记录d(A->i)距离为Dis[i]
首先有个很明显的性质d(i -> j) == d(j -> i)
然后我们想办法把图分成三部分,0 到 A中间,0左边,0右边。
0 到A中间讨论起来很简单,dis[i] == dis[A] + Dis[i],且(Dis[i] < dis[A]),形状为C,位置为 location[A] - Dis[i]
0 左边 dis[i] == dis[A] + Dis[i] ,且(Dis[i] > dis[A])
A 右边 dis[i] != dis[A] + Dis[i]
为什么可以这么讨论,因为无论是0到A中间,0左边,无论转几次向,第一次转向必定经过A。
然后单独讨论0左边的。
0左边的C形车站位置为 location[A] - Dis[i]
0左边的D形车站位置为 location[A] - Dis[B] + d(B,i) ,B为其左边最近的C形车站。
用Dis数组排序后单调栈维护0左边的C形车站。
如果是个D形车站i,它一定在B右边,即排序后在B后面。
记录当前栈顶C形车站为C,记录i与C距离为tmp,
如图

如果其为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代码:


  1. # include "rail.h"
  2. # include <iostream>
  3. # include <cstring>
  4. # include <algorithm>
  5. using namespace std;
  6. const int N = 5e3 + ;
  7. const int mod = 2e5 + ;
  8. struct node{
  9. int dis,id;
  10. bool operator <(const node & other)const{return dis < other.dis;}
  11. }l[N],r[N];
  12. int dis[N],Dis[N],t1,t2,Amx = 1e9,A,que[N],tmp,d,t,hs[mod];
  13. void add(int p)
  14. {
  15. int x = p % mod;
  16. while(hs[x] != -)
  17. {
  18. x++;
  19. if(x == mod)x = ;
  20. }
  21. hs[x] = p;
  22. }
  23. bool find(int p)
  24. {
  25. int x = p % mod;
  26. if(x < )return false;
  27. while(hs[x] != -)
  28. {
  29. if(hs[x] == p)return true;
  30. x++;
  31. if(x == mod)x = ;
  32. }
  33. return false;
  34. }
  35. void findLocation(int n, int first, int location[], int stype[])
  36. {
  37. memset(hs,-,sizeof hs);
  38. location[] = first;stype[] = ;
  39. if(n == )return;
  40. for(int i = ;i < n;i++)dis[i] = getDistance(,i),A = dis[i] < Amx ? i : A,Amx = dis[i] < Amx ? dis[i] : Amx;
  41. for(int i = ;i < n;i++)if(i != A)Dis[i] = getDistance(A,i);
  42. location[A] = first + dis[A];stype[A] = ;
  43. for(int i = ;i < n;i++)
  44. {
  45. if(i == || i == A)continue;
  46. if(dis[A] + Dis[i] == dis[i] && Dis[i] < dis[A])location[i] = location[A] - Dis[i],stype[i] = ;
  47. if(dis[A] + Dis[i] == dis[i] && Dis[i] > dis[A])l[++t1] = (node){Dis[i],i};
  48. if(dis[A] + Dis[i] != dis[i])r[++t2] = (node){dis[i],i};
  49. }
  50. sort(l + ,l + t1 + );sort(r + ,r + t2 + );
  51. if(t2)
  52. {
  53. location[que[t = ] = r[].id] = first + r[].dis;stype[r[].id] = ;add(location[r[].id]);
  54. for(int i = ;i <= t2;i++)
  55. {
  56. tmp = getDistance(r[i].id,que[t]);
  57. d = (dis[que[t]] + tmp - dis[r[i].id]) / ;
  58. if(location[que[t]] - d > location[A] && find(location[que[t]] - d))
  59. location[r[i].id] = location[que[t]] - tmp,stype[r[i].id] = ;
  60. else location[r[i].id] = first + r[i].dis,stype[r[i].id] = ,add(location[r[i].id]),que[++t] = r[i].id;
  61.  
  62. }
  63. }
  64. if(t1)
  65. {
  66. location[que[t = ] = l[].id] = location[A] - l[].dis;stype[l[].id] = ;add(location[l[].id]);
  67. for(int i = ;i <= t1;i++)
  68. {
  69. tmp = getDistance(l[i].id,que[t]);
  70. d = (Dis[que[t]] + tmp - Dis[l[i].id]) / ;
  71. if(location[que[t]] + d < first && find(location[que[t]] + d))
  72. location[l[i].id] = location[que[t]] + tmp,stype[l[i].id] = ;
  73. else location[l[i].id] = location[A] - l[i].dis,stype[l[i].id] = ,add(location[l[i].id]),que[++t] = l[i].id;
  74. }
  75. }
  76. }
 

[UOJ#24]【IOI2014】Rail的更多相关文章

  1. UOJ#24. 【IOI2014】Rail 交互题

    原文链接www.cnblogs.com/zhouzhendong/p/UOJ24.html 题解 我们将 C 型车站称为 左括号 '(', D 型车站称为右括号 ')' ,设括号 i 的位置为 p[i ...

  2. uoj#29. 【IOI2014】Holiday

    http://uoj.ac/problem/29 经过的点集一定是一个包含start的区间,为了经过这个区间内所有点,必须先到达一个区间端点,再到达另一个区间端点,剩余的步数则贪心选区间内最大价值的点 ...

  3. uoj #58. 【WC2013】糖果公园(树上莫队算法+修改操作)

    [题目链接] http://uoj.ac/problem/58 [题意] 有一棵树,结点有自己的颜色,若干询问:u,v路径上的获益,并提供修改颜色的操作. 其中获益定义为Vc*W1+Vc*W2+…+V ...

  4. uoj #5. 【NOI2014】动物园 kmp

    #5. [NOI2014]动物园 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://uoj.ac/problem/5 Description 近日 ...

  5. UOJ #148. 【NOIP2015】跳石头 二分

    #148. [NOIP2015]跳石头 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://uoj.ac/problem/148 Descripti ...

  6. Uoj #131. 【NOI2015】品酒大会 后缀数组,并查集

    #131. [NOI2015]品酒大会 统计 描述 提交 自定义测试 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项, ...

  7. UOJ#7. 【NOI2014】购票 | 线段树 凸包优化DP

    题目链接 UOJ #7 题解 首先这一定是DP!可以写出: \[f[i] = \min_{ancestor\ j} \{f[j] + (d[j] - d[i]) * p[i] + q[i]\}\] 其 ...

  8. UOJ #17. 【NOIP2014】飞扬的小鸟 背包DP

    #17. [NOIP2014]飞扬的小鸟 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4902  Solved: 1879 题目连接 http:// ...

  9. UOJ#130 【NOI2015】荷马史诗 K叉哈夫曼树

    [NOI2015]荷马史诗 链接:http://uoj.ac/problem/130 因为不能有前缀关系,所以单词均为叶子节点,就是K叉哈夫曼树.第一问直接求解,第二问即第二关键字为树的高度. #in ...

随机推荐

  1. ACM Changchun 2015 L . House Building

    Have you ever played the video game Minecraft? This game has been one of the world's most popular ga ...

  2. debian7安装icedove

    stable --icedove --esr $ cat /etc/apt/sources.list | grep "deb http://security.debian.org/ whee ...

  3. 常用C/C++预处理指令详解

    预处理是在编译之前的处理,而编译工作的任务之一就是语法检查,预处理不做语法检查.预处理命令以符号“#”开头. 常用的预处理指令包括: 宏定义:#define 文件包含:#include 条件编译:#i ...

  4. Django two

    http://www.cnblogs.com/yuanchenqi/articles/6083427.html Django: 1.安装Django pip install  django 2.创建p ...

  5. Mantis安装与配置

    什么是Mantis MantisBT is a free popular web-based bugtracking system (feature list). It is written in t ...

  6. 缓存淘汰算法之LRU实现

    Java中最简单的LRU算法实现,就是利用 LinkedHashMap,覆写其中的removeEldestEntry(Map.Entry)方法即可 如果你去看LinkedHashMap的源码可知,LR ...

  7. Leetcode 466.统计重复个数

    统计重复个数 定义由 n 个连接的字符串 s 组成字符串 S,即 S = [s,n].例如,["abc", 3]="abcabcabc". 另一方面,如果我们可 ...

  8. 九度oj 题目1494:Dota

    题目描述: 大家都知道在dota游戏中,装备是对于英雄来说十分重要的要素. 英雄们不仅可以购买单个的装备,甚至某些特定的装备组合能够合成更强的装备. 为了简化问题,我们将每个装备对于英雄的功能抽象为一 ...

  9. 【bzoj2115】[Wc2011] Xor DFS树+高斯消元求线性基

    题目描述 输入 第一行包含两个整数N和 M, 表示该无向图中点的数目与边的数目. 接下来M 行描述 M 条边,每行三个整数Si,Ti ,Di,表示 Si 与Ti之间存在 一条权值为 Di的无向边. 图 ...

  10. kb-01-a<简单搜索--dfs八皇后问题变种>

    题目描述: 在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别.要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的 ...