【NOI2018全国热身赛】小W、小J和小Z

【题目链接】

【思路要点】

  • 我们发现两个人相撞当且仅当他们开始时的相对位置和结束时相对位置发生了交换。
  • 二分答案,问题转化为了最长上升子序列。
  • 时间复杂度\(O(NLogNLogV)\)。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
const long double eps = 1e-7;
const long double INF = 1e99;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
struct info {int p, v; };
int n, k;
info a[MAXN];
bool check(long double mid) {
	static long double pos[MAXN];
	for (int i = 1; i <= n; i++)
		pos[i] = a[i].p + a[i].v * mid;
	static int dp[MAXN];
	memset(dp, 0, sizeof(dp));
	static long double low[MAXN];
	int Max = 0; low[0] = -INF;
	for (int i = 1; i <= n; i++) {
		dp[i] = upper_bound(low, low + Max + 1, pos[i] - eps) - low;
		if (dp[i] > Max) {
			Max = dp[i];
			low[Max] = pos[i];
		} else chkmin(low[dp[i]], pos[i]);
	}
	return Max + k >= n;
}
bool cmp(info a, info b) {
	if (a.p == b.p) return a.v > b.v;
	else return a.p < b.p;
}
int main() {
	read(n), read(k);
	for (int i = 1; i <= n; i++)
		read(a[i].p), read(a[i].v);
	sort(a + 1, a + n + 1, cmp);
	int tn = 1;
	for (int i = 2; i <= n; i++)
		if (a[i].p == a[tn].p && a[i].v == a[tn].v) k--;
		else a[++tn] = a[i];
	n = tn;
	long double l = 0, r = 2.5e9;
	while (l + eps < r) {
		long double mid = (l + r) / 2;
		if (check(mid)) l = mid;
		else r = mid;
	}
	long double ans = (l + r) / 2;
	if (ans > 2.4e9) printf("Forever\n");
	else printf("%.6Lf\n", (l + r) / 2);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39972971/article/details/80794351
今日推荐