题意:在一个数轴上,给出$N$个人的初始位置与速度(速度有方向),求最大的时间使得存在$N-K$个人在这一段时间内两两没有相遇。$1 \leq K \leq N \leq 10^5$
显然有二分性质,考虑二分答案,接着考虑check过程。
考虑先按照位置排序,然后我们能够发现:如果两个人能够相遇,那么它们的位置大小顺序就会发生变化(也就是产生一个逆序对)
然后就能够发现:最多的互相没有相遇的人在新的位置序列上体现为最长上升子序列,然后就能够通过$O(n)$转移得到答案。
1 #include<bits/stdc++.h>
2 #define ld long double
3 using namespace std;
4
5 inline int read(){
6 int a = 0;
7 bool f = 0;
8 char c = getchar();
9 while(!isdigit(c)){
10 if(c == '-')
11 f = 1;
12 c = getchar();
13 }
14 while(isdigit(c)){
15 a = (a << 3) + (a << 1) + (c ^ '0');
16 c = getchar();
17 }
18 return f ? -a : a;
19 }
20
21 const ld eps = 1e-10;
22 const int MAXN = 100010;
23 struct peo{
24 int pos , v;
25 }now[MAXN];
26 ld minN[MAXN];
27 int N , K , cnt;
28
29 bool operator <(peo a , peo b){
30 return a.pos < b.pos;
31 }
32
33 bool cmp(ld a , ld b){
34 return a + eps > b && a - eps < b;
35 }
36
37 bool check(ld mid){
38 cnt = 0;
39 for(int i = 1 ; i <= N ; i++){
40 ld t = now[i].pos + now[i].v * mid;
41 int k = lower_bound(minN , minN + cnt + 1 , t - eps) - minN;
42 if(k > cnt || cmp(minN[k] , t) == 0){
43 minN[k] = t;
44 if(k > cnt)
45 ++cnt;
46 }
47 }
48 return cnt + K >= N;
49 }
50
51 int main(){
52 N = read();
53 K = read();
54 for(int i = 1 ; i <= N ; i++){
55 now[i].pos = read();
56 now[i].v = read();
57 }
58 sort(now + 1 , now + N + 1);
59 ld L = 0 , R = 2e9 + 1;
60 minN[0] = -1e30;
61 while(R - L > eps){
62 ld mid = (L + R) / 2;
63 check(mid) ? L = mid : R = mid;
64 }
65 if(R > 2e9)
66 puts("Forever");
67 else
68 printf("%Lf" , L);
69 return 0;
70 }