2020杭电多校第一场1009 Leading Robots 6759 (单调栈)

2020杭电多校第一场1009 Leading Robots 6759 (单调栈)

题目

http://acm.hdu.edu.cn/showproblem.php?pid=6759

题意

给了n个机器人的初始位置p和加速度a,起始速度都是0,问起跑后,问你有多少个机器人当过第一名,即在某一时刻,有唯一一个机器人如果冲在最前面则他是当过第一名的,注意并列第一则不算第一,赛道是无限长的。

题解

可以利用单调栈去储存当过第一的机器人。
先把机器人按照位置最远(位置相同按照加速度大在前面,加速度小的放前面会wa)排序。
然后遍历,只要能超过栈顶元素就可以放到栈中,但是如果还能超越栈顶后面的元素,那么栈顶的这个元素就pop掉(因为他不可能领头)。
然后用map去记录栈里面元素p和a出现的次数,如果有一个以上p和a相同的,说明存在并排的机器人,不能算进答案。

AC代码

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
using namespace std;
#define ll long long
#define INF 999999999
#define mem(a,b) memset(a,b,sizeof(a))
#define PI acos(-1)
const int maxn = 5e5+5;
const ll mod = 1e9+7;
const double eps = 1e-6L;
struct node
{
	ll local,a;
	double tim;
} car[maxn],s[maxn];
bool cmp(node x,node y)
{
	if(x.local!=y.local)
		return x.local>y.local;
	return x.a>y.a;
}
double cal(node x,node y)
{
	if(y.a!=x.a)
		return 1.0*(x.local-y.local)/(y.a - x.a);
	else if(x.local==y.local) return 0;
	else return INF;
}
int dcmp(double a,double b){
    if(-eps<=max(a,b)-min(a,b)&&max(a,b)-min(a,b)<=eps)return 0;
    if(a<b)return -1;
    else
        return 1;
}
int main()
{
//	freopen("1.txt","r",stdin);
//	freopen("ans.txt","w",stdout);
	int T;
	scanf("%d",&T);
	while(T--)
	{
		int n;
		scanf("%d",&n);
		for(int i=0; i<n; i++)
		{
			scanf("%lld %lld",&car[i].local,&car[i].a);
		}
		sort(car,car+n,cmp);
		map<pair<ll,ll>,int> mp;
		mp.clear();
		stack<node> s;
		car[0].tim = INF;
		s.push(car[0]);
		mp[{car[0].local,car[0].a}]++;
		for(int i = 1; i<n;i++)
		{
			node x;
			x = s.top();
			if(car[i].a<x.a)
				continue;
			if(car[i].a==x.a&&car[i].local!=x.local)
				continue;
			double res = cal(x,car[i]);
			while(s.size()>1&&dcmp(res,x.tim)<=0)
			{
				s.pop();
				x = s.top();
				res = cal(x,car[i]);
			}
			car[i].tim = res;
			x = car[i];
			s.push(x);
			mp[{car[i].local,car[i].a}]++;
		}
		int ans=0;
		while(!s.empty())
		{
			node x = s.top();
			s.pop();
			if(mp[{x.local,x.a}] == 1)
			{
				ans++;
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
1
10
2560 1
2483 154
2252 308
1867 462
1328 616
635 770
2564 67
2564 15
2567 38
2570 19
*/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值