题解【洛谷P5959】[POI2018]Plan metra
一道比较神仙的构造题。
首先确定 \(1\) 到 \(n\) 的路径长度,不妨设其长为 \(m\) 。
通过观察发现,\(m\) 就是 \(\min_{1<i<n}\{dist_{1,i} + dist_{i,n}\}\)。
如果所有的 \(| dist_{1, i} - dist_{i, n} |\) 都相等,那么可以特判一下:
- 首先将 \(1\) 与 \(n\) 连接起来,路径长度为 \(| dist_{1, i} - dist_{i, n} |\) ;
- 对于每一个 \(\forall 1<i<n\) :
- 如果\(dist_{1,i}>dist_{i,n}\),那么将 \(i\) 与 \(1\) 连接,长度为 \(dist_{1,i}\) ;
- 如果\(dist_{1,i} \leq dist_{i,n}\) ,那么将 \(i\) 与 \(n\)连接,长度为 \(dist_{i, n}\) 。
 
若点 \(i\) 满足 \(dist_{1,i} + dist_{i,n} = m\),则 \(i\) 在 \(1\) 到 \(n\) 的路径上。
否则可以求出 \(i\) 到 \((1, n)\) 路径的距离和 \(i\) 在路径上的“投影”的
位置,查找位置可以使用二分查找。
将 \(i\) 挂在路径上对应的点上即可。
如果找不到可以挂起的位置或者 \(1\) 到 \(n\) 的路径上有几个点重复就无解。
注意特判 \(n=2\) 的情况。
代码如下(刚好 \(100\) 行…):
#include <bits/stdc++.h>
#define DEBUG fprintf(stderr, "Passing [%s] line %d\n", __FUNCTION__, __LINE__)
#define itn int
#define gI gi
#define mk make_pair
using namespace std;
inline int gi()
{
	int f = 1, x = 0; char c = getchar();
	while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
	while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
	return f * x;
}
const int maxn = 500003;
int sz, ddd, len, n, m = 1000000007, d1[maxn], dn[maxn], dis[maxn], jlx[maxn];
struct Node
{
	int id, dis;
} a[maxn];
struct Ans
{
	int u, v, w;
} ans[maxn];
inline bool cmp(Node x, Node y) {return x.dis < y.dis;}
inline void sub1_getans()
{
	puts("TAK");
	printf("1 %d %d\n", n, len);
	for (int i = 2; i < n; i+=1)
	{
		if (d1[i] < dn[i]) printf("1 %d %d\n", i, d1[i]);
		else printf("%d %d %d\n", n, i, dn[i]);
	}
	return;
}
inline int Binary_Search(int x)
{
	int l = 1, r = sz;
	while (l <= r)
	{
		int mid = (l + r) >> 1;
		if (a[mid].dis == x) return mid;
		else if (a[mid].dis < x) l = mid + 1;
		else r = mid - 1;
	}
	return -1;
}
int main()
{
	n = gi();
	if (n == 2) //特判
	{
		puts("TAK\n1 2 1");
		return 0;
	}
	d1[1] = dn[n] = 0;
	for (int i = 2; i < n; i+=1) d1[i] = gi();
	for (int i = 2; i < n; i+=1) dn[i] = gi(), jlx[i] = abs(d1[i] - dn[i]);
	bool fl = true;
	for (int i = 3; i < n; i+=1) if (jlx[i] != jlx[i - 1]) {fl = false; break;}
	if (fl) {len = jlx[2]; sub1_getans(); return 0;} //特判
	for (int i = 2; i < n; i+=1) m = min(m, d1[i] + dn[i]);
	a[++sz] = (Node){1, 0};
	d1[n] = dn[1] = m;
	for (int i = 2; i < n; i+=1)
		if (d1[i] + dn[i] == m) a[++sz] = (Node){i, d1[i]};
	a[++sz] = (Node){n, d1[n]};
	sort(a + 1, a + 1 + sz, cmp);
	for (int i = 2; i < n; i+=1)
	{
		dis[i] = d1[i] - (d1[i] + dn[i] - m) / 2;
	}
	for (int i = 1; i < sz; i+=1)
	{
		if (a[i].dis == a[i + 1].dis) {puts("NIE"); return 0;}
		ans[++ddd] = (Ans){a[i].id, a[i + 1].id, a[i + 1].dis - a[i].dis};
	}
	for (int i = 2; i < n; i+=1)
	{
		int nowlen = d1[i] + dn[i];
		if (nowlen != m)
		{
			int find_jl = Binary_Search(dis[i]); //二分挂起的位置
			if (((d1[i] + dn[i] - m) & 1) || find_jl == -1) {puts("NIE"); return 0;}
			ans[++ddd] = (Ans){a[find_jl].id, i, (d1[i] + dn[i] - m) / 2};
		}
	}
	puts("TAK");
	for (int i = 1; i <= ddd; i+=1) printf("%d %d %d\n", ans[i].u, ans[i].v, ans[i].w);
	return 0;
}
另:这份代码在洛谷上 AC 了, 但是在 BZOJ 上会 WA, 不知道为什么……
题解【洛谷P5959】[POI2018]Plan metra的更多相关文章
- 【BZOJ5100】[POI2018]Plan metra 构造
		[BZOJ5100][POI2018]Plan metra Description 有一棵n个点的无根树,每条边有一个正整数权值,表示长度,定义两点距离为在树上的最短路径的长度. 已知2到n-1每个点 ... 
- bzoj5100 [POI2018]Plan metra 构造
		5100: [POI2018]Plan metra Time Limit: 40 Sec Memory Limit: 128 MBSec Special JudgeSubmit: 189 Sol ... 
- bzoj千题计划249:bzoj5100: [POI2018]Plan metra
		http://www.lydsy.com/JudgeOnline/problem.php?id=5100 1.找到d1[i]+dn[i] 最小的点,作为1到n链上的点 2.令链长为D,若abs(d1[ ... 
- 题解 洛谷P5018【对称二叉树】(noip2018T4)
		\(noip2018\) \(T4\)题解 其实呢,我是觉得这题比\(T3\)水到不知道哪里去了 毕竟我比较菜,不大会\(dp\) 好了开始讲正事 这题其实考察的其实就是选手对D(大)F(法)S(师) ... 
- 题解 洛谷 P3396 【哈希冲突】(根号分治)
		根号分治 前言 本题是一道讲解根号分治思想的论文题(然鹅我并没有找到论文),正 如论文中所说,根号算法--不仅是分块,根号分治利用的思想和分块像 似却又不同,某一篇洛谷日报中说过,分块算法实质上是一种 ... 
- 题解-洛谷P5410 【模板】扩展 KMP(Z 函数)
		题面 洛谷P5410 [模板]扩展 KMP(Z 函数) 给定两个字符串 \(a,b\),要求出两个数组:\(b\) 的 \(z\) 函数数组 \(z\).\(b\) 与 \(a\) 的每一个后缀的 L ... 
- 题解-洛谷P4229 某位歌姬的故事
		题面 洛谷P4229 某位歌姬的故事 \(T\) 组测试数据.有 \(n\) 个音节,每个音节 \(h_i\in[1,A]\),还有 \(m\) 个限制 \((l_i,r_i,g_i)\) 表示 \( ... 
- 题解-洛谷P4724 【模板】三维凸包
		洛谷P4724 [模板]三维凸包 给出空间中 \(n\) 个点 \(p_i\),求凸包表面积. 数据范围:\(1\le n\le 2000\). 这篇题解因为是世界上最逊的人写的,所以也会有求凸包体积 ... 
- 题解-洛谷P4859 已经没有什么好害怕的了
		洛谷P4859 已经没有什么好害怕的了 给定 \(n\) 和 \(k\),\(n\) 个糖果能量 \(a_i\) 和 \(n\) 个药片能量 \(b_i\),每个 \(a_i\) 和 \(b_i\) ... 
随机推荐
- 离线部署ArcGIS Runtime for Android100.5.0
			环境 系统:window 7 JDK:1.8.0_151 Maven:3.6.1 Android Studio:2.3 ArcGIS Runtime SDK for Android:100.5.0 1 ... 
- 二、继续学习(主要参考Python编程从入门到实践)
			操作列表 具体内容如下: # 操作列表 # 使用for循环遍历整个列表. # 使用for循环处理数据是一种对数据集执行整体操作的不错的方式. magicians = ['alice', 'david' ... 
- Perl-统计某电路面积、功耗占比(NVDIA2019笔试)
			1.perl脚本 open IN, "<", "data.txt" or die "The file does not exist!" ... 
- 论文阅读笔记(十六)【AAAI2018】:Region-Based Quality Estimation Network for Large-Scale Person Re-Identification
			Introduction (1)Motivation: 当前的行人重识别方法都只能在标准的数据集上取得好的效果,但当行人被遮挡或者肢体移动时,往往效果不佳. (2)Contribution: ① 提出 ... 
- linq to sql 比较字符串形式的时间
			where Convert.ToDateTime(t.Date.Trim()).CompareTo(Convert.ToDateTime("2009/9/9")) >= 0 ... 
- 关于Spring注入参数到static静态参数失败问题处理。解决Autowired annotation is not supported on static fields的问题
			直接贴代码 把注入参数的注解加到set方法上面去即可. 因为这是一个工具类用到的config,所以一开始没有加@Component,还是依然为空,加上之后就正常能注入了 
- tensorflow张量排序
			本篇记录一下TensorFlow中张量的排序方法 tf.sort和tf.argsort # 声明tensor a是由1到5打乱顺序组成的 a = tf.random.shuffle(tf.range( ... 
- 【15】ML项目流程与正交化
			结构化机器学习项目 一 ML项目流程 1,确立目标(确定开发/测试集 + 唯一最优化指标) 确定开发/测试集:开发/测试集应尽可能接近将来应用场景中的数据. 划分数据集:开发集和测试集大小足以评估模型 ... 
- 安装Kibana到Linux(源码)
			运行环境 系统版本:CentOS Linux release 7.3.1611 (Core) 软件版本:Kibana-7.1.0 硬件要求:最低2核4GB 安装过程 1.源码安装JDK 1.1.从官网 ... 
- hdu 2187 悼念512汶川大地震遇难同胞——老人是真饿了(贪心)
			新人题:n2的排序就可以过 #include <stdio.h> #include <stdlib.h> int main() { int c,n,i,j,o; ],b[],m ... 
