zoukankan      html  css  js  c++  java
  • noi.ac89A 电梯

    题目

    思路

    首先按照(t)排序!!!!

    首先考虑一个暴力(dp)

    (f[i])表示前(i)个人到达地点所需要的时间。

    那么就有如下的转移

    [f_i = min_{1 le j le i}(max(f_j,t_i) + max{w_{j + 1} ... w_i} * 2) ]

    这样复杂度是(o(n^2))

    考虑优化上面的(dp)

    因为已经按照(t)从小到大排过序了,所以如果(w_i le w_{i + 1})那么第(i)这个人就一定是和第(i+1)个人一起跟优秀。所以就可以把第(i)人剔除掉。

    用单调栈可以完成上面的工作。

    现在就变成了一个(t)单调递增,(w)单调递减的序列

    然后再去看上面的(dp),我们可以把它分成两段。
    (if(f_j le t_i))

    [f_i=t_i + max{w_{j+1}...w_i} * 2 ]

    (if(f_j > t_i))

    [f_i = f_j + max{w_{j+1}...w_i} * 2 ]

    因为(w)数组单减,所以上面的式子(max{w_{j+1}...w_i})是肯定是(w_{j+1})

    所以上面的(dp)式子可以这样写

    (if(f_j le t_i))

    [f_i=t_i + w_{j+1} * 2 ]

    (if(f_j > t_i))

    [f_i = f_j + w_{j+1} * 2 ]

    因为(f)数组是递增的,所以第一种转移肯定一前一部分,第二种转移是后一部分。可以找到他们的分界点(p)

    对于(p)(p)之前的,因为(t_i)固定了,所以只要找到最小的(w_{j + 1})就行了。显然(w_{p+1})最小

    对于(p)之后的,就是要找最小的(f_j+w_{j+1}*2),用线段树维护一下。

    代码

    /*
    * @Author: wxyww
    * @Date:   2019-03-24 19:59:19
    * @Last Modified time: 2019-03-24 20:43:41
    */
    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #include<ctime>
    using namespace std;
    typedef long long ll;
    const ll INF = 4e9,N = 1000000 + 100;
    #define int ll
    ll read() {
    	ll x=0,f=1;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 x*f;
    }
    int b[N],top,tree[N << 2], f[N];
    struct node {
    	int p,w;
    }a[N];
    void update(int rt,int l,int r,int pos,int c) {
    	if(l == r) {
    		tree[rt] = c;
    		return;
    	}
    	int mid = (l + r) >> 1;
    	if(pos <= mid) update(rt << 1,l,mid,pos,c);
    	else update(rt << 1 | 1,mid + 1,r,pos,c);
    	tree[rt] = min(tree[rt << 1],tree[rt << 1 | 1]);
    }
    int query(int rt,int l,int r,int L,int R) {
    	if(L <= l && R >= r) return tree[rt];
    	int mid = (l + r) >> 1;
    	int ans = INF;
    	if(L <= mid) ans = min(ans,query(rt << 1,l,mid,L,R));
    	if(R > mid) ans = min(ans,query(rt << 1 | 1,mid + 1,r,L,R));
    	return ans;
    }
    bool cmp(const node &A,const node &B) {
    	return A.p < B.p;
    }
    signed main() {
    	int n = read();
    	for(int i = 1;i <= n;++i) a[i].p = read(),a[i].w = read();
    
    	sort(a + 1,a + n + 1,cmp);
    
    	for(int i = 1;i <= n;++i) {
    		while(a[i].w >= a[b[top]].w && top) top--;
    		b[++top] = i;
    	}
    	
    	int p = 0;
    	for(int i = 1;i <= top;++i) {
    		while(p < i - 1 && f[p + 1] <= a[b[i]].p) ++p;
    		f[i] = a[b[i]].p + a[b[p + 1]].w * 2;
    		if(p + 1 <= i - 1) f[i] = min(f[i],query(1,1,top,p + 1,i - 1));
    		update(1,1,top,i,f[i] + a[b[i + 1]].w * 2);
    	}
    	cout<<f[top];
    	return 0;
    }
    
  • 相关阅读:
    如何使用 Python 创建一名可操控的角色玩家
    Unity查找物体的四大主流方法及区别
    JavaFX桌面应用开发-鼠标事件和键盘事件
    profiler-gpu分析记录
    JavaFX桌面应用开发-Button(按钮)与事件
    CodeCombat代码全记录(Python学习利器)--Kithgard地牢代码1
    spine骨骼动画组件使用详解
    微信小程序animation
    LeetCode--不同路径
    Learning opencv续不足(七)线图像的设计D
  • 原文地址:https://www.cnblogs.com/wxyww/p/10590615.html
Copyright © 2011-2022 走看看