noip2019集训测试赛(六)A.炮艇大赛之正式赛

Description

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

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

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

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

问比赛什么时候结束。


Input

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

接下来一行包含 n 个不同的整数 di ( 0di<L0≤di<L )

接下来一行包含 n 个不同的整数 vi ( vi109|vi|≤10^9 )


Output

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


Solution

通过手推,可以发现只有相邻的两个参赛者才会最先相遇,所以这个问题变成了维护一个环相邻两元素的相遇时间。

我们可以用小根堆维护相邻两元素的相遇时间,为了便捷,我使用了优先队列。每次将相遇时间最短的一组相遇出队,看其中哪个能量值小,就把它标记为挂掉。此时会产生新的相邻,将其入队。第n-1次相遇的时间就是答案。

要注意,已经挂掉的人是不会与别人相遇的,所以相遇的两人之中若有人挂掉应忽略此次相遇。


Code

#include<bits/stdc++.h>
using namespace std;
struct data{
	int t1,t2,x,y;
	bool operator < (const data &v)const{
		return double(t1)/double(t2)>double(v.t1)/double(v.t2);
	}
}u;
struct xyj{
	int d,v,id;
	bool operator < (const xyj &y)const{
		return d<y.d;
	}
}a[100010];
int gcd(int x,int y){
	return y==0?x:gcd(y,x%y);
}
priority_queue<data>q;
int n,nxt[100010],L;
int pre[100010];
bool out[100010];
void work(int x,int y){
	int t1,t2;
	if(a[x].v>a[y].v) swap(x,y);
	t1=(a[x].d+L-a[y].d)%L;
	t2=a[y].v-a[x].v;
	q.push((data){t1,t2,x,y});
} 
int main(){
	scanf("%d%d",&n,&L);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i].d);
		a[i].id=i;
	}
	for(int i=1;i<=n;i++)
	scanf("%d",&a[i].v);
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++){
		pre[i]=(i==1?n:i-1);
		nxt[i]=(i==n?1:i+1);
	}
	for(int i=1;i<=n;i++){
		int x=(i==n?1:i+1);
		work(i,x);
	}
	int tot=0;
	while(q.size()){
		u=q.top(); q.pop();
		if(out[u.x]||out[u.y]) continue;
		tot++; 
		if(tot==n-1){//第n-1次相遇时间即是答案
			int s=gcd(u.t1,u.t2);
			printf("%d/%d",u.t1/s,u.t2/s);
			return 0;
		}
		int lose=a[u.x].id>a[u.y].id?u.y:u.x;
		out[lose]=true;
		int x=pre[lose],y=nxt[lose];
		nxt[x]=y,pre[y]=x,work(x,y);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章