[JZOJ3187]【GDOI2013模拟8】的士
题目
描述
题目大意
在一个数轴上,有些人要从某个点到达另一个点。
出租车从最左端出发,将所有人送到它们的目的地,最终到达最右边的点。
出租车只能做一个乘客,并且可以在图中将乘客丢下。
问最短时间。
思考历程
一看就觉得是神仙题,
往DP方向思考,没有一点点长进……
压根就没有想过贪心……
然而这题又没得打暴力,于是一分都没有拿。
正解
面对这种神仙题,为什么我没有想到贪心……
首先将有用功加入答案中。
出租车走过的路径一定连在一起的,如果我们添加一条从到的路径,就能保证它最终能到达点。这样路径就构成了一个环。
可以通过各个点将数轴分成很多段,每一段上有一些往左走的路,有一些往右走的路。
大多时候这些向左走和向右走的路径条数是不一样的,但我们求的是环(欧拉回路)。
于是我们相减,取绝对值,强制添加路径。
这样搞出来之后可能不会连通,但由于有条从到的路径,如果不连通,一定可以有种花费同样代价的方式使得它们串成一个欧拉回路。所以直接添加就好。
那么我们差分处理一下就搞定了。
然后还有一种神奇的方法。
同样要加上到的路径。
首先将有用功加入答案中,然后的具体做法比较神奇:将起点和终点分别排序,下标相同的坐标相减取绝对值,加入答案中。
然后就没了。
这是什么神仙做法?
根据我的理解,这也是搞出欧拉回路,然后贪心地将起点和终点配对,即连在一起。
配对的时候排序,然后两两配,这样是最小的。我自己想了一个不完整的证明:假设有和,可以证明。在数轴上分类讨论就可以证明了。
仔细想想,我发现这似乎已经无视了可以把乘客中途扔下车的操作(除了将几个欧拉回路连在一块之外)!
路径分成了很多段,如果拆开来这样做,就相当于可以中途将乘客赶下车,这样一定是没有问题的。这几段中,中间的每个交点既是起点,又是终点,它们自己和自己配对,不会优于与真正的起点终点配对。
这个东西感性理解一下吧……不会证明。
代码
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
int n,end;
struct Op{
int x,ty;
} o[N*2];
int m;
inline bool cmp(const Op &a,const Op &b){
return a.x<b.x;
}
long long ans;
int main(){
scanf("%d%d",&n,&end);
o[++m]={end,-1};
o[++m]={0,1};
for (int i=1;i<=n;++i){
int x,y;
scanf("%d%d",&x,&y);
ans+=abs(x-y);
o[++m]={x,-1};
o[++m]={y,1};
}
sort(o+1,o+m+1,cmp);
for (int i=2,j=o[1].ty;i<=m;++i){
ans+=1ll*(o[i].x-o[i-1].x)*abs(j);
j+=o[i].ty;
}
printf("%lld\n",ans);
return 0;
}