zoukankan      html  css  js  c++  java
  • UOJ #236. 【IOI2016】railroad

    Description

    Anna 在一个游乐园工作。她负责建造一个新的过山车铁路。她已经设计了影响过山车速度的 nn 个特殊的路段(方便起见标记为 00 到 n−1n−1)。现在 Anna 必须要把这些特殊的路段放在一起并提出一个过山车的最后设计。为了简化问题,你可以假设过山车的长度为零。

    对于 00 和 n−1n−1 之间的每个 ii,这个特殊的路段 ii 具有如下两个性质:

    当进入这个路段时,有一个速度限制:过山车的速度必须小于或等于 sisi km/h(每小时千米),
    当离开这个路段时,过山车的速度刚好是 titi km/h,不管过山车进入该路段时的速度如何。

    最后完成的过山车设计是一个以某种顺序包含这 nn 个特殊路段的单一铁路线。这 nn 个路段中的每一个应当被使用刚好一次。连续的路段之前用铁轨来连接。Anna 应该选择这 nn 个路段的顺序,然后确定每段铁轨的长度。铁轨的长度以米来衡量,可以是任意的非负整数(可以为零)。

    两个特殊路段之间的每 11 米铁轨可以将过山车的速度减慢 11 km/h。在这个过山车铁路的起点,过山车按照 Anna 选择的顺序进入第一个特殊路段时的速度是 11 km/h。

    最后的设计还必须满足以下要求:

    过山车在进入这些特殊路段时不能违反任一个速度限制;
    过山车的速度在任意时刻为正。

    在所有子任务中(子任务 33 除外),你的任务是找出这些路段之间铁轨的最小可能总长度(这些路段之间铁轨总长度的最小值)。对于子任务 33 你只需要检查是否存在一个有效的过山车设计,使得每段铁轨的长度为零。

    Solution

    我们可以把这个过程看成速度的起落,于是我们把速度离散成点
    对于每组((s_i,t_i)),(s_i->t_i)连边,这样形成很多条边
    我们可以把速度的变化看作这个图中的一条欧拉路,这样也得先满足欧拉路的条件
    经过每一段区间 ([x,x+1]) 的向左的边和向右的边的差的绝对值不超过(1)(因为这是一个反复横跳的过程)
    这样我们就得到了每一个点的度数 (in[i]) (向左-向右的边数)
    如果 (in[i]<0) 我们要做的是让速度变慢,那么就加入 (in[i])条代价为 (x_i-x_{i-1}) 的边,从而满足度数条件
    如果 (in[i]>0) 因为速度增大是不需要代价的,所以直接把度数变成 (0) 即可

    所以前面一部分相当于是把有交的边先处理好(同一个连通块)
    最后由于图要连通,所以再做一遍最小生成树,实质是构造出不同连通块的摆放顺序,使得代价最小

    #include<bits/stdc++.h>
    #include "railroad.h"
    using namespace std;
    typedef long long ll;
    const int N=400005;
    int n,b[N],num=0,m,fa[N],sum[N];
    inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    struct sub{
    	int x,y,z;
    	bool operator <(const sub &p)const{return z<p.z;}
    }e[N];
    long long plan_roller_coaster(std::vector<int> s, std::vector<int> t) {
        n = (int) s.size();
    	 for(int i=0;i<n;i++)b[++num]=s[i],b[++num]=t[i];
    	 sort(b+1,b+num+1);m=unique(b+1,b+num+1)-b-1;
    	 for(int i=1;i<=m;i++)fa[i]=i;
    	 for(int i=0;i<n;i++){
    		 s[i]=lower_bound(b+1,b+m+1,s[i])-b;
    		 t[i]=lower_bound(b+1,b+m+1,t[i])-b;
    		 fa[find(t[i])]=find(s[i]);
    		 sum[s[i]]--,sum[t[i]]++;
    	 }
    	 int cnt=0;ll ans=0;
    	 sum[1]++;sum[m]--;
    	 if(find(1)!=find(m))fa[find(m)]=find(1);
    	 for(int i=m;i>1;i--){
    		 if(sum[i]){
    			 if(sum[i]>0)ans+=1ll*sum[i]*(b[i]-b[i-1]);
    			 sum[i-1]+=sum[i];fa[find(i)]=find(i-1);
    		 }
    		 e[++cnt]=(sub){i-1,i,b[i]-b[i-1]};
    	 }
    	 sort(e+1,e+cnt+1);
    	 for(int i=1;i<=cnt;i++){
    		 int x=e[i].x,y=e[i].y;
    		 if(find(x)==find(y))continue;
    		 fa[find(y)]=find(x);
    		 ans+=e[i].z;
    	 }
        return ans;
    }
    
    
  • 相关阅读:
    django 在保存数据前进行数据校验
    itertools
    python 发送请求
    python 异常处理
    python 对redis 键值对的操作
    python 对redis key的基本操作
    python 操作redis数据
    一只青蛙一次可以跳1阶或者2阶,n阶,有多少种到达终点的方式。
    Django 自定义扩展命令
    关于函数可变参数
  • 原文地址:https://www.cnblogs.com/Yuzao/p/8490631.html
Copyright © 2011-2022 走看看