#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);

评测方式


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

  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代码:


# include "rail.h"
# include <iostream>
# include <cstring>
# include <algorithm>
using namespace std;
const int N = 5e3 + ;
const int mod = 2e5 + ;
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] != -)
{
x++;
if(x == mod)x = ;
}
hs[x] = p;
}
bool find(int p)
{
int x = p % mod;
if(x < )return false;
while(hs[x] != -)
{
if(hs[x] == p)return true;
x++;
if(x == mod)x = ;
}
return false;
}
void findLocation(int n, int first, int location[], int stype[])
{
memset(hs,-,sizeof hs);
location[] = first;stype[] = ;
if(n == )return;
for(int i = ;i < n;i++)dis[i] = getDistance(,i),A = dis[i] < Amx ? i : A,Amx = dis[i] < Amx ? dis[i] : Amx;
for(int i = ;i < n;i++)if(i != A)Dis[i] = getDistance(A,i);
location[A] = first + dis[A];stype[A] = ;
for(int i = ;i < n;i++)
{
if(i == || i == A)continue;
if(dis[A] + Dis[i] == dis[i] && Dis[i] < dis[A])location[i] = location[A] - Dis[i],stype[i] = ;
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 + ,l + t1 + );sort(r + ,r + t2 + );
if(t2)
{
location[que[t = ] = r[].id] = first + r[].dis;stype[r[].id] = ;add(location[r[].id]);
for(int i = ;i <= t2;i++)
{
tmp = getDistance(r[i].id,que[t]);
d = (dis[que[t]] + tmp - dis[r[i].id]) / ;
if(location[que[t]] - d > location[A] && find(location[que[t]] - d))
location[r[i].id] = location[que[t]] - tmp,stype[r[i].id] = ;
else location[r[i].id] = first + r[i].dis,stype[r[i].id] = ,add(location[r[i].id]),que[++t] = r[i].id; }
}
if(t1)
{
location[que[t = ] = l[].id] = location[A] - l[].dis;stype[l[].id] = ;add(location[l[].id]);
for(int i = ;i <= t1;i++)
{
tmp = getDistance(l[i].id,que[t]);
d = (Dis[que[t]] + tmp - Dis[l[i].id]) / ;
if(location[que[t]] + d < first && find(location[que[t]] + d))
location[l[i].id] = location[que[t]] + tmp,stype[l[i].id] = ;
else location[l[i].id] = location[A] - l[i].dis,stype[l[i].id] = ,add(location[l[i].id]),que[++t] = l[i].id;
}
}
}
 

[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. day 37 MySQL行(记录)的详细操作

    MySQL行(记录)的详细操作   阅读目录 一 介绍 二 插入数据INSERT 三 更新数据UPDATE 四 删除数据DELETE 五 查询数据SELECT 六 权限管理 一 介绍 MySQL数据操 ...

  2. redis--py链接redis【转】

    请给原作者点赞--> 原文链接 一.redis redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链 ...

  3. debian软raid

    http://www.linuxidc.com/Linux/2013-06/86487.htm  

  4. Android CTS - Cannot run program "aapt"/ Fail to run aapt on .../apk installed but AaptParser failed

    今天同事碰到cts的一些问题,跑到某个apk的时候,就提示如下错误: Cannot run program "aapt": error=2. No such file or dir ...

  5. 蓝桥杯Java输入输出相关

    转载自:http://blog.csdn.net/Chen_Tongsheng/article/details/53354169 一.注意点 1. 类名称必须采用public class Main方式 ...

  6. Android 资源文件local.properties使用以及Gradle文件中的值、Manifests文件中的值

    这篇也是因为Gradle存储密钥问题一路填坑总结的,期初连.properties创建都有疑问 因为当时是在Android下查看新建的properties一直没法看到 因为Gradle Scripts是 ...

  7. Leetcode 466.统计重复个数

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

  8. Python socket粘包问题(初级解决办法)

    server端配置: import socket,subprocess,struct from socket import * server=socket(AF_INET,SOCK_STREAM) s ...

  9. JQuery常用的HTML页控制取值、赋值

    1,关于tab页签 获取当前页签的属性: var tabsSelect=$("#easytabs").tabs("getSelected"); var titl ...

  10. MySQL可供选择的存储引擎

    备注:以下关于5.7版本的内容是来源于官方文档:https://dev.mysql.com/doc/refman/5.7/en/storage-engines.html 以下关于5.6版本的内容,一部 ...