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);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章