搭船
题目描述
有一条河,沿河有 m + 1 m+1 m+1 个村庄,按照次序依次编号为 0 0 0 到 m m m,相邻村庄之间的距离都是 1 1 1。
某天早上,船夫在 0 0 0 号村庄开始他的工作,当天想要搭船的村民有 n n n 个,其中第 i i i 个村民要从 a i a_i ai 号村庄搭船到 b i b_i bi 号村庄。完成运输所有村民的工作后,船夫需要将船停到 m m m 号村庄上。
船夫的船舱足够大,可以同时搭载任意多名村民。显然,同时搭载多名村民,可以减少重复路程。请帮助船夫计算一下,为了把所有村民运到各自的目的地,在当天的工作中,船只最少需要行走多少距离?1
输入格式
第一行:两个整数 n n n 和 m m m;
第二行到第 n + 1 n+1 n+1 行:第 i + 1 i+1 i+1 行有两个整数表示 a i a_i ai 和 b i b_i bi。
输出格式
单个整数:表示船只最少需要行走多少路程才能把所有村民运到他们的目的地。
样例
输入数据#1
2 10
2 8
6 4
输出数据#1
14
输入数据#2
8 15
1 12
3 1
3 9
4 2
7 13
12 11
14 11
14 13
输出数据#2
27
数据范围
-
对于 30 % 的数据满足: 1 ≤ n ≤ 30 , 3 ≤ m ≤ 1 0 3 。 对于 30\%的数据满足:1\leq n\leq 30,3\leq m\leq 10^3。 对于30%的数据满足:1≤n≤30,3≤m≤103。
-
对于 50 % 的数据满足: 1 ≤ n ≤ 10000 , 3 ≤ m ≤ 1 0 9 。 对于 50\% 的数据满足:1\leq n\leq 10000,3\leq m\leq 10^9。 对于50%的数据满足:1≤n≤10000,3≤m≤109。
-
对于 100 % 的数据满足: 1 ≤ n ≤ 300000 , 3 ≤ m ≤ 1 0 9 。 对于 100\% 的数据满足:1\leq n\leq 300000,3\leq m\leq 10^9。 对于100%的数据满足:1≤n≤300000,3≤m≤109。
-
0 ≤ a i , b i ≤ m 0\leq a_i,b_i \leq m 0≤ai,bi≤m
一、审题
意思是:每个村民要搭船从 a a a 到 b b b,船从 0 0 0 点出发,送完村民后到 m m m 点,问船行驶的最短距离。
二、看数据范围
n < = 300000 n<=300000 n<=300000,就知道算法的复杂度是 O ( n ) O(n) O(n) 或 O ( n log n ) O(n\log n) O(nlogn); m < = 1 0 9 m<=10^9 m<=109,能看出不能将每个位置都用数组保存起来,并且要用
long long
。三、思路
- 首先,顺路的村民(即 a < b a<b a<b)不用考虑,并且不会影响最终的答案。因为船从 0 0 0 出发,最终要停到 m m m,因此顺路的村民直接搭船即可。搭载他们的总路程就是 m m m。
- 逆路的村民无论如何都是需要逆向开船的,而上面我们知道顺路的村民不需要考虑。因此在输入时,我们 只把逆路的村民记录在结构体里。
- 对于逆路的村民,我们考虑优化:
- 如果一个村民的路程被另一个村民的路程完全覆盖,被覆盖的那个村民的路程不用考虑,因为在搭载另一个村民时他“顺路”。
- 如果两个村民的路程中间有一部分有重合(只有端点重合也可以包括在内),那可以把他俩的路程放到一起去送,这样能节省一些路程。节省的路程就是重合部分的路程的一来一回的距离。
- 综合以上分析,为了方便处理。我们可以把逆路的村民的路程按左端点从小到大的排序,如果左端点相同,按右端点从大到小排序。
#include <bits/stdc++.h>
using namespace std;
long long n, m, x, y, ll, sum;
struct ppp {
long long l, r;
bool operator<(const ppp& ppr) const {
if (l != ppr.l) return l < ppr.l;
return r > ppr.r;
}
} a[300005];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> x >> y;
if (x > y) a[++ll] = {y, x};
}
sort(a + 1, a + ll + 1);
for (int i = 1; i <= ll;) {
long long j, st = a[i].l, en = a[i].r;
for (j = i + 1; j <= ll; j++) {
if (a[j].l <= en)
en = max(en, a[j].r);
else
break;
}
sum += 2 * (en - st);
i = j;
}
cout << sum + m;
return 0;
}
本题来自Topscoding ↩︎