[JZOJ4944]Monument

题目大意

n 个人在一条无穷的数轴上,一开始第i个人在 pi 上,从零时刻开始以每秒 vi 的速度移动。
现在你最多可以删除 K 个人,最大化T使得在前 T 时间内不存在任意两个人曾经相遇(位置相同即相遇,包括追及)。

1kn105,|pi|,|vi|109


题目分析

首先我们可以想到二分答案。那么怎么判定答案 t 是否可行呢?
可以发现,两个人没有相遇当且仅当在零时刻两人的相对顺序和t时刻一致。
那么我们删掉最少的人=保留最多的人使得这些相对顺序不发生变化。
那可以一开始将所有人按照 pi 排序,然后判定时计算每个人的位置,做一个最长上升子序列就可以得到最多能保留的人数。
A 为二分上界,然后就O(nlognlogA)解决问题了。


代码实现

使用lower_bound来实现LIS真短!

#include <algorithm>
#include <iostream>
#include <cfloat>
#include <cstdio>
#include <cctype>

using namespace std;

typedef long double db;

int read()
{
    int x=0,f=1;
    char ch=getchar();
    while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();
    while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
    return x*f;
}

const db INF=2e+9;
const db EPS=1e-5;
const int N=100050;

int v[N],p[N],kth[N];
db f[N],x[N];
db ans;
int n,K;

bool judge(db t)
{
    for (int i=1;i<=n;i++) x[i]=1.0*v[kth[i]]*t+1.0*p[kth[i]];
    for (int i=1;i<=n;i++) f[i]=DBL_MAX/3;
    f[0]=-DBL_MAX/3;
    int len=0;
    for (int i=1;i<=n;i++)
    {
        int id=lower_bound(f,f+len+1,x[i])-f;
        f[id]=x[i],len=max(len,id);
    }
    return n-len<=K;
}

void binary_search()
{
    for (db l=0.0,r=INF,mid;r-l>EPS;)
    {
        mid=(l+r)/2.0;
        if (judge(mid)) l=(ans=mid)+EPS;
        else r=mid-EPS;
    }
}

bool cmp(int x,int y){return p[x]<p[y];}

int main()
{
    freopen("monument.in","r",stdin),freopen("monument.out","w",stdout);
    n=read(),K=read();
    for (int i=1;i<=n;i++) p[i]=read(),v[i]=read(),kth[i]=i;
    sort(kth+1,kth+1+n,cmp);
    binary_search();
    if (judge(ans+1.0)) printf("Forever\n");
    else printf("%.4lf\n",(double)ans);
    fclose(stdin),fclose(stdout);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值