本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
【CCPC】2022广州站 E. Elevator | 二维数点
题目链接
题目
There are nn elevators participating in a speed race starting at second 0 in a building of m floors numbered 1 through m.
The i-th elevator will start at second at floor 1 and will ascend at the speed of 1 floor per second. Besides, there is a button on each floor except floor 1 and floor m, which, if pressed, will make the first elevator that reaches this floor stop for 1 second. If more than one elevator reaches a floor at the same time, only the elevator with the smallest index will be regarded as the first one. There are no buttons pressed now, but you can press the buttons on some floors before the start of the race. Notice that you can not press the button after the race starts.
Now you wonder whether you will be able to manipulate the race by pressing the buttons to make the i-th elevator be the first to reach floor m, and how many buttons you have to press at least if you can. If more than one elevator reaches floor m at the same time, only the elevator with the smallest index will be regarded as the first one.
题目大意
在一栋从第 1 层到第 层的大楼里有 个电梯进行比赛,编号为 。第 个电梯在第 时刻从第 1 层出发,所有电梯的速度都为 1,即每经过一个单位时间将会向上运行一个楼层。
从第 2 层到第 ,每层都有一个按钮。在电梯们的比赛开始之前,你可以按下若干个按钮。如果按下按钮,会使第一个到达该层的电梯停止一个时间单位。如果同时有多个电梯到达,只对其中编号最小的电梯生效。
问如果想让第 个电梯第一个到达第 层(如果有多个电梯同时到达,只算编号最小的电梯第一个到达。),最少需要按下多少个按钮?对 分别计算答案并输出。
思路
显然如果想让第 个电梯取得胜利,需要让电梯 出发的时刻加上暂停的时间大于 ,让电梯 出发的时刻加上暂停的时间不小于 。即答案是电梯 的出发时刻中小于等于 的值与 的差再加上电梯 中出发的时刻小于 的值与 的差。
首先先求把所有比 小的元素变成 需要按多少次按钮。开个结构体记一下值和下标,以值为第一关键字下标为第二关键字排序,则对于排序后的第 个元素,这部分答案显然是 。
然后我们考虑怎样使 前面的元素都小于 ,我们只需要再按 前面不超过 的元素的数量次按钮即可。该问题可以用二维数点解决。
代码
#include <stdio.h>
#include <algorithm>
#include <queue>
#define lowbit(x) (x&-x)
using namespace std;
using LL=long long;
const int N=500005;
int s[N];
struct asdf{
int id;
LL x;
bool operator < (const asdf a) const
{
if (x!=a.x) return x<a.x;
return id<a.id;
}
}a[N];
int n,m;
LL ans[N];
void add(int t)
{
for (;t<=n;t+=lowbit(t))
s[t]++;
}
int getcnt(int t)
{
int cnt=0;
for (;t>=1;t-=lowbit(t))
cnt+=s[t];
return cnt;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i)
{
scanf("%lld",&a[i].x);
a[i].id=i;
}
sort(a+1,a+1+n);
for (int i=2;i<=n;++i)
ans[a[i].id]=ans[a[i-1].id]+(i-1)*(a[i].x-a[i-1].x);
for (int i=1;i<=n;++i)
{
ans[a[i].id]+=getcnt(a[i].id);
add(a[i].id);
}
for (int i=1;i<=n;++i)
{
if (ans[i]>m-2) printf("-1\n");
else printf("%lld\n",ans[i]);
}
return 0;
}