炮艇大赛之正式赛(单调队列)

题目描述

给定一个长度为L的环形赛道, n个人在上面赛艇. 每个人的速度都不相同, 假如为正则顺时针走, 否则逆时针走. 当两个人相遇时, 编号小的那个人就会出局. 当只剩下一个人时, 这个人就获得胜利.(L<=1e9 , n<=1e5)

问: 多久以后游戏结束.

#include<bits/stdc++.h>
using namespace std;
int read(){
    int x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int get_gcd(int a,int b){
    if(b==0) return a;
    return get_gcd(b,a%b);
}
const int N=1e5+5;
int n,L;
struct boat{int w,d,v;}a[N];
bool cmpd(boat a,boat b){
    return a.d<b.d;
}
struct record{
    int id[2];double t;
    inline record(){}
    inline record(int u,int v){
        if(a[u].v>a[v].v) swap(u,v);
        t=(double)((a[u].d-a[v].d+L)%L)/(a[v].v-a[u].v);//相遇时间 
        id[0]=u;id[1]=v;
        if(a[id[0]].w<a[id[1]].w) swap(id[0],id[1]);//id[0]留下,id[1]出局 
    }
    inline int operator <(const record &a) const{return t>a.t;}//从小到大排 
};
static int nxt[N],lst[N],del[N]; 
int main(){
    n=read();L=read();
    for(int i=1;i<=n;i++){
        a[i].w=i;a[i].d=read();
    }
    for(int i=1;i<=n;i++){
        a[i].v=read();
    }
    //因为每次相遇的只能是位置相邻的两人,所以把相邻两人相遇所需要的时间用一个堆维护起来
    sort(a+1,a+n+1,cmpd);
    priority_queue<record> q;
    q.push(record(1,n));
    for(int i=2;i<=n;i++) q.push(record(i,i-1));
    for(int i=1;i<=n;i++) nxt[i]=(i+1)%n==0?n:(i+1)%n;
    for(int i=1;i<=n;i++) lst[i]=(i-1)%n==0?n:(i-1)%n;
    //每次找到最早相遇的两个人,记录其中一人出局,并将新产生的相邻的两人加入堆中
    for(int i=n;i>=3;i--){
        record rec;
        while(1){
            rec=q.top();q.pop();
            int pd=1;
            if(del[rec.id[0]]||del[rec.id[1]]) pd=0;
            if(pd) break;
        }
        del[rec.id[1]]=1;
        nxt[lst[rec.id[1]]]=nxt[rec.id[1]];
        lst[nxt[rec.id[1]]]=lst[rec.id[1]];
        nxt[rec.id[1]]=lst[rec.id[1]]=-1;
        q.push(record(rec.id[0],nxt[rec.id[0]]));
        q.push(record(rec.id[0],lst[rec.id[0]])); //可能在前面也可能在后面产生新的相邻两人 
    }
    record rec;
    while(1){
        rec=q.top();q.pop();
        int pd=1;
        if(del[rec.id[0]]||del[rec.id[1]]) pd=0;
        if(pd) break;
    }
    //得到最后是哪两人相遇
    if(a[rec.id[0]].v>a[rec.id[1]].v) swap(rec.id[0],rec.id[1]); 
    int ans1=(a[rec.id[0]].d-a[rec.id[1]].d+L)%L;
    int ans2=a[rec.id[1]].v-a[rec.id[0]].v;
    if(ans1==0||ans2==0) printf("0\n");
    else{
        int gcd=get_gcd(ans1,ans2);
        printf("%d/%d",ans1/gcd,ans2/gcd);
    }
    return 0;    
}

 

posted @ 2019-08-05 15:43  Mistletoes  阅读(114)  评论(0编辑  收藏  举报