标签:碰撞 c++ stream ORC n+1 情况 停止 name image
平面上有 \(n\) 个点。第 \(i\) 点的坐标是 \((x_i, y_i)\)。你有两个长度为 \(k\) 的水平平台。每个平台可以放置在平面上的任何地方,但它应该水平放置(在同一个 \(y\) 坐标上),平台的边框都为整数。如果平台的左边框是 \((x,y)\),那么右边框是 \((x+k,y)\),边界之间的所有点(包括边框)都属于平台。
请注意,平台可以共享公共点(重叠),不需要将两个平台放置在同一个 \(y\) 坐标上。
当你把两个平台放在一个平面上时,所有的点都开始沿着 \(y\) 坐标下降。如果某个点在某个时刻与某个平台发生碰撞,则该点停止并且被保存。从未与任何平台碰撞的点都会丢失。
任务是找出可以保存的最大的点数的两个平台放置的最优化方案。
必须完成 \(t\) 个独立的测试用例。
我们观察发现:\(y\) 坐标没有用处且最优情况两个板子肯定都在某个点的横坐标上,同时两块板子还不重叠。我们由此可以先计算出每个数往后延伸 \(k\) 可以够到的最远距离,然后问题就变成了这样:
给出一个数组 \(a\),求出\(max_{i = 1}^{n} (a_i + max_{j = a_i+i}^{n} a_j)\)。
我们发现,\(max_{j = a_i+i}^{n} a_j\) 我们可以用线段树维护,时间复杂度为 \(O(n)\)。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 2e5+10;
int T;
int n, k, x, Ans;
int a[N], b[N];
struct node
{
int l, r, maxn;
}t[N*4];
void build(int p, int l, int r)
{
t[p].l = l;
t[p].r = r;
if (l == r)
{
t[p].maxn = b[l];
return ;
}
int mid = (l+r)/2;
build(p*2, l, mid);
build(p*2+1, mid+1, r);
t[p].maxn = max(t[p*2].maxn, t[p*2+1].maxn);
}
int query(int p, int l, int r)
{
if (l > r) return 0;
if (t[p].l >= l && t[p].r <= r) return t[p].maxn;
int mid = (t[p].l + t[p].r) / 2;
int ans = -0x3f3f3f3f;
if (l <= mid) ans = max(ans, query(p*2, l, r));
if (r > mid) ans = max(ans, query(p*2+1, l, r));
return ans;
}
int main()
{
scanf("%d", &T);
while (T--)
{
Ans = 0;
scanf("%d %d", &n, &k);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
sort(a+1, a+n+1);
for (int i = 1; i <= n; i++) scanf("%d", &x);
x = 1;
for (int i = 1; i <= n; i++)
{
while (a[x] <= a[i] + k && x != n+1) x++;
b[i] = x - i;
}
build(1, 1, n);
for (int i = 1; i <= n; i++)
{
Ans = max(Ans, b[i] + query(1, b[i]+i, n));
}
cout << Ans << ‘\n‘;
}
return 0;
}
标签:碰撞 c++ stream ORC n+1 情况 停止 name image
原文地址:https://www.cnblogs.com/david24/p/14378053.html