Island Tour(岛之旅)
时间限制:2s 内存限制:1024MB
【原题地址】
【问题描述】
Atcoder群岛由N个岛屿组成,这些岛屿由N座桥连接。
岛屿编号从1到N,第i座桥(1≤i≤N−1)双向连接岛屿i和i+1,而第N座桥双向连接岛屿N和1。除了过桥,没有办法在岛屿之间旅行。在岛上,定期进行从岛 X1 出发并按顺序访问岛X2 ,X3 ,…,XM 的旅游。
旅游团可能会经过不在参观之列的岛屿,并且在旅程期间跨越桥梁的总次数被定义为旅程的长度。更准确地说,ATour是满足以下所有条件的l+1个岛a0 ,a1 ,…,al 的序列,
其长度定义为l:
-对于所有j (0≤j≤l−1),岛aj 和aj+1 通过桥直接连接。
-存在一些0=y1 <y2 <⋯<yM =l,使得对于所有k (1≤k≤M),a_yk =X_k 。
由于财政困难,群岛将关闭一座桥梁,以减少维护费用。
确定待关闭桥梁的最佳选择时,行程的最小可能长度。
【输入格式】
输入内容由标准输入法提供,格式如下
N M
X1 X2 … XM
3≤N≤2×10^5
2≤M≤2×10^5
1≤X^k ≤N
X_k !=X_k+1 (1≤k≤M−1)
-所有输入值均为整数。
【输出格式】
将答案打印为整数。
【样例输入】
样例一、
3 3
1 3 2
样例二、
4 5
2 4 2 4 2
【样例输出】
样例一、
2
样例二、
8
【样例说明】
对于第一个测试用例,
对于第二个测试用例,同一个岛可能在X1 ,X2 ,…,XM 中出现多次。
【解题思路】
老汉使用到的是IMOS的解题方式
本题是求停掉一座桥时,最短旅程。
先停掉0号桥,也就是1岛到n岛的桥,获取本次最短旅程(可以理解为岛屿号数最小的旅游岛左边的桥),发现只有当下一个旅游点与上一旅游点的桥停掉时,数值才会发生变化,获取本次旅程,接下来依次求取,获得最小值
主要思路来源于:点击此处跳转至题解
代码注释有详细过程
【代码】
package ABC338_D_IslandTour;
import java.util.Scanner;
import java.util.Vector;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int m = scan.nextInt();
// 用于存放对应岛屿数据
Vector<Integer>[] arr = new Vector[200001];
for (int i = 0; i < 200001; i++) {
arr[i] = new Vector<Integer>();
}
int[] x = new int[m];
// 保存每个断点选择的最短旅程
long ans = 0;
// 获取断点设置在1岛到n岛之间的桥,也就是0桥时,最短旅程
for (int i = 0; i < m; i++) {
x[i] = scan.nextInt();
// 保存好该岛次序
arr[x[i]].add(i);
if (i != 0) {
// 取断点后,最短旅程只有两地之间的距离
ans += Math.abs(x[i] - x[i - 1]);
}
}
// 存放几次数据的最小值
long res = ans;
// 断点取到n-1即可,此时最右边的点在最左边,已经是最后一个可能答案
for (int i = 1; i <= n - 1; i++) {
// 获取所有旅游地次序,以免发生重复旅游时漏掉
for (int t = 0; t < arr[i].size(); t++) {
// 获取次序
int j = arr[i].get(t);
// 改变更改断点后上一岛到当前岛的旅程变化
if (j >= 1) {
int k = (x[j - 1] - i + n) % n;
ans += Math.abs(n - k) - k;
}
// 改变更改断点后当前岛到下一岛的旅程变化
if (j < m - 1) {
int k = (x[j + 1] - i + n) % n;
ans += Math.abs(n - k) - k;
}
}
// 获取最小旅程
res = Math.min(ans, res);
}
System.out.println(res);
scan.close();
}
}