【HDU6136】 Death Podracing 【堆】【模拟】

Description

炮艇大赛是一项危险的比赛。为了赢得这场比赛,参赛者可能会牺牲自己的生命。

参赛者将会在一条长度为 L L L的环形轨道上比赛。在比赛开始时( 0 0 0时刻),所有参赛者站在轨道不同的位置上,其中第 i i i 名参赛者站在位置 d i ( 0 ≤ d i &lt; L ) d_i(0≤d_i&lt;L) di(0di<L) 上。然后比赛开始。每位参赛者驾驶着它的炮艇,速度为 v i v_i vi (速度可以为正,可以为负,也可以为 0 0 0。速度为正表示参赛者顺时针移动,速度为负表示参赛者逆时针移动)。每位参赛者的速度都不同。

i i i 名参赛者有 i i i 点能量值。在比赛过程中,参赛者们可能会相遇(此处相遇指的是参赛者们在同一时刻恰好落在同一地点)。每两位参赛者 i , j i,j i,j 相遇时,能量值低的参赛者将被击毙出局。

当赛场上只剩下一个人时,比赛结束。

问比赛什么时候结束。

Input

第一行包含两个正整数 n , L ( 1 ≤ n ≤ 1 0 5 , 1 ≤ L ≤ 1 0 9 ) n,L(1≤n≤10^5,1≤L≤10^9) n,L(1n105,1L109)

接下来一行包含 n 个不同的整数 d i ( 0 ≤ d i &lt; L ) d_i(0≤d_i&lt;L) di(0di<L)

接下来一行包含 n 个不同的整数 v i ( ∣ v i ∣ ≤ 1 0 9 ) v_i(|v_i|≤10^9) vi(vi109)

Output

输出一个分数 X / Y X/Y X/Y 表示结束时刻,其中 g c d ( X , Y ) = 1 gcd(X,Y)=1 gcd(X,Y)=1 。若答案为 0 0 0,应只输出“0”(不含引号)。

题解:

用堆模拟就好。
先算出所有相邻两个人相遇的时间,丢进堆里,每次取出时间最小的一对人,移出其中一个,添加新的相邻两个人相遇的时间入堆即可。最后堆中剩下的一对人的相遇时间就是答案。

代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
typedef long long ll;
using namespace std;
const int N=100005;
int n,m,right[N],left[N];
ll l;
bool out[N];
ll gcd(ll x,ll y){
	return y?gcd(y,x%y):x;
}
struct data{
	ll d,v;
	int id;
	bool operator < (const data &n) const{
		return d<n.d;
	}
}a[N],b[N];
struct num{
	ll a,b;
	int x,y;
	num(){x=0;y=1;}
	num(ll aa,ll bb,int xx,int yy){a=aa;b=bb;x=xx;y=yy;}
	bool operator < (const num &n) const{
		return a*n.b>b*n.a;
	}
};
priority_queue<num> pq;
ll get(ll xl,ll xr,bool f){
	if(f){
		if(xr<xl){
			return xl-xr;
		}else{
			return xl+l-xr;
		}
	}else{
		if(xr>xl){
			return xr-xl;
		}else{
			return xr+l-xl;
		}
	}
}
num calc(ll s,ll v,int x,int y){
	return (num){s,v,x,y};
}
int main(){
	scanf("%d%lld",&n,&l);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i].d);
		a[i].id=i;
		left[i]=i-1;
		right[i]=i+1;
	}
	left[1]=n;
	right[n]=1;
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i].v);
	}
	sort(a+1,a+n+1);
	for(int i=1;i<=(n==2?1:n);i++){
		int j=i+1;
		if(j>n){
			j=1;
		}
		bool f1=a[i].v<0,f2=a[j].v<0;
		int s,t;
		if(abs(a[i].v)>abs(a[j].v)){
			s=a[i].d;
			t=a[j].d;
		}else{
			s=a[j].d;
			t=a[i].d;
		}
		if(f1==f2){
			pq.push(calc(get(s,t,f1),abs(a[i].v-a[j].v),i,j));
		}else{
			pq.push(calc(get(a[i].d,a[j].d,f1),abs(a[i].v)+abs(a[j].v),i,j));
		}
	}
	while(pq.size()>1){
		num now=pq.top();
		pq.pop();
		if(out[now.x]||out[now.y]){
			continue;
		}
		if(a[now.x].id>a[now.y].id){
			swap(now.x,now.y);
		}
		out[now.x]=1;
		int ll=left[now.x],rr=right[now.x];
		if(ll==rr){
			break;
		}
		right[ll]=rr;
		left[rr]=ll;
		bool f1=a[ll].v<0,f2=a[rr].v<0;
		int s,t;
		if(abs(a[ll].v)>abs(a[rr].v)){
			s=a[ll].d;
			t=a[rr].d;
		}else{
			s=a[rr].d;
			t=a[ll].d;
		}
		if(f1==f2){
			pq.push(calc(get(s,t,f1),abs(a[ll].v-a[rr].v),ll,rr));
		}else{
			pq.push(calc(get(a[ll].d,a[rr].d,f1),abs(a[ll].v)+abs(a[rr].v),ll,rr));
		}
	}
	num res=pq.top();
	ll g=gcd(res.a,res.b);
	res.a/=g;
	res.b/=g;
	printf("%lld/%lld\n",res.a,res.b);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值