【XSY2541】炮艇大赛之正式赛(堆)

题面

Description

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

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

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

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

问比赛什么时候结束。

Input

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

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

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

Output

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

Sample Input & Sample Output

【样例输入1】

2 4
0 2
3 2

【样例输出1】

扫描二维码关注公众号,回复: 7014873 查看本文章
2/1

【样例输入2】

10 100
56 89 62 71 7 24 83 1 47 52
9 -16 34 -38 47 49 -32 17 39 -9

【样例输出2】

37/7

HINI

对于\(20\%\)的数据, \(1≤n≤10^3,1≤L≤10^4,|vi|≤10^4\)

对于\(40\%\)的数据, \(1≤n≤10^4,1≤L≤10^5,|vi|≤10^5\)

对于所有数据, \(1≤n≤10^5,1≤L≤10^9,|vi|≤10^9,0≤wi≤n\)

题解

第一种解法比较直观,我们按淘汰的顺序将\(n-1\)个人逐一淘汰。有一个比较容易证明的结论:假设现在环上还剩\(k\)个人,那么接下来的第一次淘汰发生必然是环上的相邻的两个人相撞。 注意到这一个人如果被淘汰不会对后续过程有任何影响,如果我们能找出谁是这一次被淘汰的,直接把这个人从当前状态中删除,就能把问题变成一个只有 \(k-1\) 个人的子问题,我们也用同样的方法求解这个子问题。

于是我们可以用一个堆维护环上当前所有相邻人(距离意义上的相邻)相遇的时间,从中取出最小值,就能找到第一个被淘汰的人,这个人删除后,原本不相邻的两个人就相邻了,同样求出他们的相遇时间,加入堆中,重复执行这一过程,直到找到最后一个被淘汰的人为止。

维护两个人的相遇时间可以直接分情况\(O(1)\)维护。开始时将\(n\)个人中的相邻的人的相遇时间插入堆,每次插入为\(O(log(n))\),所以这一段时间复杂度为\(O(nlog(n))\)。之后一共要删除\(n\)个人,每次删除时还要将一个元素插入堆需要\(O(log(n))\),所以这一段的时间就是\(O(log(n))\)

所以总时间复杂度为\(O(nlog(n))\)

完整代码如下:

#include<bits/stdc++.h>
 
#define N 100010
 
using namespace std;
 
struct Time
{
    int a,b;
    double t;
    bool operator < (const Time &a) const
    {
        return a.t<t;//按相遇时间排序
    }
}ans;
 
struct data
{
    int d,v,id;
}a[N];
 
int n,L,l[N],r[N];
bool flag[N];
 
priority_queue<Time>q;//小根堆
 
bool cmp(data a,data b)//按距离排序
{
    return a.d<b.d;
}
 
double intersection(data a,data b,int x)//O1求相遇时间
{
    if(a.d>b.d)
    {
        if(a.v>b.v)
        {
            if(!x)return (double)(L-(a.d-b.d))/(double)(a.v-b.v);
            if(x==1)return (double)L-(a.d-b.d);
            return (double)a.v-b.v;
        }
        else
        {
            if(!x)return (double)(a.d-b.d)/(double)(b.v-a.v);
            if(x==1)return (double)a.d-b.d;
            return (double)b.v-a.v;
        }
    }
    else
    {
        if(a.v>b.v)
        {
            if(!x)return (double)(b.d-a.d)/(double)(a.v-b.v);
            if(x==1)return (double)b.d-a.d;
            return (double)a.v-b.v;
        }
        else
        {
            if(!x)return (double)(L-(b.d-a.d))/(double)(b.v-a.v);
            if(x==1)return (double)L-(b.d-a.d);
            return (double)b.v-a.v;
        }
    }
}
 
int gcd(int a,int b)
{
    if(!b)return a;
    return gcd(b,a%b);
}
 
int main()
{
    scanf("%d%d",&n,&L);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i].d);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i].v);
    for(int i=1;i<=n;i++)
        a[i].id=i;
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++)
    {
        l[i]=(i==1?n:i-1);//l[i]为当前环上i左边相邻的点的编号
        r[i]=(i==n?1:i+1);//r[i]同理
        q.push((Time){l[i],i,intersection(a[l[i]],a[i],0)});//将相邻两人的相遇时间放进队列
    }
    while(!q.empty())
    {
        Time now=q.top();
        q.pop();
        if(flag[now.a]||flag[now.b])continue;
        ans=now;
        if(a[now.a].id<a[now.b].id)
        {
            flag[now.a]=true;
            l[now.b]=l[now.a];
            r[l[now.b]]=now.b;
            if(l[now.b]!=now.b)q.push((Time){l[now.b],now.b,intersection(a[l[now.b]],a[now.b],0)});
        }
        else
        {
            flag[now.b]=true;
            r[now.a]=r[now.b];
            l[r[now.a]]=now.a;
            if(r[now.a]!=now.a)q.push((Time){now.a,r[now.a],intersection(a[now.a],a[r[now.a]],0)});
        }
    }
    int x=(int)intersection(a[ans.a],a[ans.b],1);
    int y=(int)intersection(a[ans.a],a[ans.b],2);
    int g=gcd(x,y);
    printf("%d/%d\n",x/g,y/g);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ez-lcw/p/11348642.html