#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. MIP启发式算法:遗传算法 (Genetic algorithm)

    *本文主要记录和分享学习到的知识,算不上原创 *参考文献见链接 本文主要讲述启发式算法中的遗传算法.遗传算法也是以local search为核心框架,但在表现形式上和hill climbing, ta ...

  2. cyg-apt update 升级报错

    现象: $ cyg-apt updatecyg-apt: downloading: http://box-soft.com/setup-2.bz2cyg-apt: downloading: http: ...

  3. SSM网上商城项目 01

    开发环境与技术选型 操作系统:win7 IDE:Eclipse neno JDK:1.8 数据库:mysql5.6 Dao层:mybatis.数据库连接池(德鲁伊druid) 缓存:redis3.0. ...

  4. Selenium WebDriver- 使用Frame中的HTML源码内容操作Frame

    #encoding=utf-8 import unittest import time from selenium import webdriver from selenium.webdriver i ...

  5. js常见的方法

    Ajax请求 jquery ajax函数 我自己封装了一个ajax的函数,代码如下: var Ajax = function(url, type success, error) { $.ajax({ ...

  6. Python socket粘包问题(最终解决办法)

    套接字: 就是将传输层以下的协议封装成子接口 对于应用程序来说只需调用套接字的接口,写出的程序自然是遵循tcp或udp协议的 实现第一个功能个:实现:通过客户端向服务端发送命令,调取windows下面 ...

  7. JDBC 学习笔记(一)—— JDBC 基础

    1. 什么是 JDBC JDBC,Java Database Connectivity(Java 数据库连接),是一组执行 SQL 语句的 Java API. JDBC,是 Java SE(Java ...

  8. BFC浅析

    1.定义 BFC(Block formatting context)即"块级格式化上下文".它是一个独⽴的渲染区域,只有Block-level box参与, 它规定了内部的Bloc ...

  9. 337. House Robber III(包含I和II)

    198. House Robber You are a professional robber planning to rob houses along a street. Each house ha ...

  10. [POI2007]MEG-Megalopolis (树状数组,Dfs序)

    题目描述 Solution 这道题考试的时候竟然没有仔细想,结果只拿了暴力分... 其实就是一个 DFS序+树状数组. 我们先把用 DFS 把它变成一个序列,同时记录它们的 \(siz\). 那么我们 ...