【WC模拟】Monument

题目大意

一条直线上有n个人,第i个的初始位置是pi,做速度为vi的匀速运动(速度是矢量)。给定一个k,你最多可以去掉k个人,然后在T时间后有两个人相遇。最大化这个T。如果可以永远不相遇输出Forever

1≤k≤n≤100000 |pi|,|vi|≤ 109

分析

首先可以看出答案是可以二分的。

接下来的思路非常重要。

考虑对于当前二分的答案mid,两个人满足什么条件会相遇,容易得到是:pi+vi*mid≥pj+vj*mid 且 pi < pj

先给每个人按pi排序,然后得到的序列就是pi从小到大的。接下来又要满足上式。为了使消除的人数尽量少,问题就相当于求最长上升子序列了。

时间复杂度 O(nlog2n)

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N=100005;

typedef long long LL;

typedef double db;

const db z=1e-4,R=2e9+1,INF=1e9*(R+1);

int n,m,p[N],v[N],Left,Right,Mid;

db l,r,mid,f[N];

struct data
{
    int p,v;
}A[N];

char c;

int read()
{
    int x=0,sig=1;
    for (c=getchar();c<'0' || c>'9';c=getchar()) if (c=='-') sig=-1;
    for (;c>='0' && c<='9';c=getchar()) x=x*10+c-48;
    return x*sig;
}

bool cmp(data a,data b)
{
    return a.p<b.p;
}

int main()
{
    freopen("monument.in","r",stdin); freopen("monument.out","w",stdout);
    n=read(); m=read();
    for (int i=1;i<=n;i++)
    {
        A[i].p=read(); A[i].v=read();
    }
    sort(A+1,A+n+1,cmp);
    for (int i=1;i<=n;i++)
    {
        p[i]=A[i].p; v[i]=A[i].v;
    }
    for (l=0,r=R,mid=(l+r)/2;r-l>=z;mid=(l+r)/2)
    {
        memset(f,127,sizeof(f));
        f[n]=-INF;
        for (int i=1;i<=n;i++)
        {
            db t=p[i]+v[i]*mid;
            for (Left=1,Right=n,Mid=Left+Right>>1;Left<Right;Mid=Left+Right>>1)
                if (f[Mid]>t) Left=Mid+1;else Right=Mid;
            if (f[Left]<t) Left--;
            if (Left>0) f[Left]=t;
        }
        if (f[m]>INF) r=mid;else l=mid;
    }
    if (r==R) printf("Forever\n");else printf("%.4lf\n",mid);
    fclose(stdin); fclose(stdout);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值