• 【2020杭电多校round1 1009】HDU6759 Leading Robots


    题目大意

    题目链接

    (n)个机器人,每个机器人有一个初始位置(p_i)和加速度(a_i)。在(t)时刻,该机器人的速度是(v_i(t)a_icdot t)

    现在所有机器人同时启动,请问无限长的时间之内,会有多少个机器人,至少在一个时刻“领先”?我们说一个机器人领先,是指在这个时刻,它的位置,严格大于其他所有机器人。

    数据范围:(1leq nleq 50000)(0leq p_i,a_ileq 2^{31})

    本题题解

    物理学上有这样一个公式:

    [s=p+frac{1}{2}at^2 ]

    其中(p)是初始位置,(a)是加速度,(t)是时间,(s)是路程(也就是在(t)时刻的位置)。

    利用这个公式,我们可以计算出,两个机器人(i,j)(假设(a_i>a_j), (p_i<p_j)),(i)何时会追上(j)。这相当于解这样一个关于(t)的方程:

    [p_i+frac{1}{2}a_it^2=p_j+frac{1}{2}a_jt^2 ]

    可以解得:

    [t=sqrt{2cdot frac{(p_j-p_i)}{(a_i-a_j)}} ]

    回到本题。先将这些机器人,按加速度从小到大排序(加速度相同时按初始位置从小到大排)。然后依次考虑每个机器人,维护一个单调栈,栈里的机器人加速度递增,每一个机器人会在某一时刻超过前一个机器人,并成为领先者(因此他们的初始位置一定是递减的)。

    对于当前机器人,栈里的其他机器人,加速度一定小于等于它。拿当前机器人(i)和栈顶的机器人(j)比较((a_igeq a_j)):

    • 如果(p_igeq p_j),则(j)永远也无法领先了,将其出栈。
    • 否则,如果(p_i<p_j)(此时一定有(a_i>a_j),因为(a)相同的机器人是按位置从小到大排序的),那(i)一定会在某个时刻追上(j)。这个时刻可以用我们上述的方程解出来,不妨记为(t_1)。此时,如果栈里有(geq 2)元素,考虑(j)前面的那个机器人(k),计算出(j)追上(k)的时刻,不妨记为(t_2)。如果(t_2geq t_1),说明(j)永远不可能领先了,将其出栈。

    如此重复,直到栈顶的元素(j),不满足上述两条,说明我们已经排除了所有“在(i)加入后,不可能再领先的机器人”。此时再将(i)入栈即可。

    值得一提的是,判断(t_2geq t_1)时,不需要真的开根号、解出来。只需要移项,转化为乘法。这样可以避免精度误差。

    时间复杂度(O(nlog n))

    后记:我们可以进一步思考一下这种做法的本质。其实是把(t^2)当成(x),把(s)当成(y),这样一个二次函数,就被转化为了一次函数。而一次函数上的这种追及问题,是很经典的:bzoj1007 水平可见的直线

    参考代码:

    //problem:hdu6759
    #include <bits/stdc++.h>
    using namespace std;
    
    #define pb push_back
    #define mk make_pair
    #define lob lower_bound
    #define upb upper_bound
    #define fi first
    #define se second
    #define SZ(x) ((int)(x).size())
    
    typedef unsigned int uint;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    
    template<typename T>inline void ckmax(T& x,T y){x=(y>x?y:x);}
    template<typename T>inline void ckmin(T& x,T y){x=(y<x?y:x);}
    
    const int MAXN=5e4;
    int n;
    struct Robot_t{
    	ll p,a;
    }p[MAXN+5];
    bool cmp(Robot_t lhs,Robot_t rhs){
    	//按加速度从小到大排,加速度相同按位置从小到大排
    	if(lhs.a == rhs.a)
    		return lhs.p < rhs.p;
    	return lhs.a < rhs.a;
    }
    bool check(const Robot_t& a,const Robot_t& b,const Robot_t& c){
    	assert(a.a < b.a && b.a < c.a);
    	// return b追上a的时间 >= c追上b的时间
    	return (b.p-a.p) * (b.a-c.a) - (c.p-b.p) * (a.a-b.a) >= 0;
    }
    int sta[MAXN+5],top;
    void solve_case(){
    	cin>>n;
    	map<pair<ll,ll>,int>mp;
    	for(int i=1;i<=n;++i){
    		cin>>p[i].p>>p[i].a;
    		mp[mk(p[i].p,p[i].a)]++;
    	}
    	sort(p+1,p+n+1,cmp);
    	top=0;
    	for(int i=1;i<=n;++i){
    		while(top){
    			if(p[sta[top]].p <= p[i].p)
    				--top;
    			else if(top>1 && check(p[sta[top-1]],p[sta[top]],p[i]))
    				--top;
    			else break;
    		}
    		sta[++top] = i;
    	}
    	int ans=top;
    	for(int i=1;i<=top;++i){
    		if(mp[mk(p[sta[i]].p,p[sta[i]].a)] > 1)
    			ans--;
    	}
    	cout<<ans<<endl;
    }
    int main() {
    	int T;cin>>T;while(T--){
    		solve_case();
    	}
    	return 0;
    }
    
  • 相关阅读:
    innodb中的锁
    41. First Missing Positive
    268. Missing Number
    154. Find Minimum in Rotated Sorted Array II(循环数组查找)
    局部最小值(二分)
    92. Reverse Linked List II 翻转链表II
    leetcode Reverse Nodes in k-Group翻转链表K个一组
    Mysql分区、分表、分库
    字符串循环移位(2次翻转的思路)
    android源码中,在系统多媒体数据库中增加一个字段
  • 原文地址:https://www.cnblogs.com/dysyn1314/p/13360880.html
Copyright © 2020-2023  润新知