Description
炮艇大賽是一項危險的比賽。爲了贏得這場比賽,參賽者可能會犧牲自己的生命。
參賽者將會在一條長度爲 L 的環形軌道上比賽。在比賽開始時(0時刻),所有參賽者站在軌道不同的位置上,其中第 i 名參賽者站在位置 di ( ) 上。然後比賽開始。每位參賽者駕駛着它的炮艇,速度爲 vi (速度可以爲正,可以爲負,也可以爲0。速度爲正表示參賽者順時針移動,速度爲負表示參賽者逆時針移動)。每位參賽者的速度都不同。
第 i 名參賽者有 i 點能量值。在比賽過程中,參賽者們可能會相遇(此處相遇指的是參賽者們在同一時刻恰好落在同一地點)。每兩位參賽者 i,j 相遇時,能量值低的參賽者將被擊斃出局。
當賽場上只剩下一個人時,比賽結束。
問比賽什麼時候結束。
Input
第一行包含兩個正整數 n,L ( )
接下來一行包含 n 個不同的整數 di ( )
接下來一行包含 n 個不同的整數 vi ( )
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);
}
}