题目链接

Kill ‘Em All

Introduce

Ivan plays an old action game called Heretic. He’s stuck on one of the final levels of this game, so he needs some help with killing the monsters.
The main part of the level is a large corridor (so large and narrow that it can be represented as an infinite coordinate line). The corridor is divided into two parts; let’s assume that the point $x=0$ is where these parts meet.
The right part of the corridor is filled with $n$ monsters — for each monster, its initial coordinate $x_i$ is given (and since all monsters are in the right part, every $x_i$ is positive).
The left part of the corridor is filled with crusher traps. If some monster enters the left part of the corridor or the origin (so, its current coordinate becomes less than or equal to $0$), it gets instantly killed by a trap.
The main weapon Ivan uses to kill the monsters is the Phoenix Rod. It can launch a missile that explodes upon impact, obliterating every monster caught in the explosion and throwing all other monsters away from the epicenter. Formally, suppose that Ivan launches a missile so that it explodes in the point $c$. Then every monster is either killed by explosion or pushed away. Let some monster’s current coordinate be $y$, then:

  • if $c=y$, then the monster is killed;
  • if $y<c$, then the monster is pushed $r$ units to the left, so its current coordinate becomes $y−r$;
  • if $y>c$, then the monster is pushed $r$ units to the right, so its current coordinate becomes $y+r$.
    Ivan is going to kill the monsters as follows: choose some integer point $d$ and launch a missile into that point, then wait until it explodes and all the monsters which are pushed to the left part of the corridor are killed by crusher traps, then, if at least one monster is still alive, choose another integer point (probably the one that was already used) and launch a missile there, and so on.
    What is the minimum number of missiles Ivan has to launch in order to kill all of the monsters? You may assume that every time Ivan fires the Phoenix Rod, he chooses the impact point optimally.
    You have to answer $q$ independent queries.

    Input

    The first line contains one integer $q$ $(1≤q≤10^5)$ — the number of queries.
    The first line of each query contains two integers $n$ and $r$ $(1≤n,r≤10^5)$ — the number of enemies and the distance that the enemies are thrown away from the epicenter of the explosion.
    The second line of each query contains $n$ integers $x_i$ $(1≤xi≤10^5)$ — the initial positions of the monsters.
    It is guaranteed that sum of all n over all queries does not exceed $10^5$.

    Output

    For each query print one integer — the minimum number of shots from the Phoenix Rod required to kill all monsters.

    Example

    input
    2
    3 2
    1 3 5
    4 1
    5 2 3 5
    output
    2
    2

    Note

    In the first test case, Ivan acts as follows:
  • choose the point $3$, the first monster dies from a crusher trap at the point $−1$, the second monster dies from the explosion, the third monster is pushed to the point $7$;
  • choose the point $7$, the third monster dies from the explosion.
    In the second test case, Ivan acts as follows:
  • choose the point $5$, the first and fourth monsters die from the explosion, the second monster is pushed to the point $1$, the third monster is pushed to the point $2$;
  • choose the point $2$, the first monster dies from a crusher trap at the point $0$, the second monster dies from the explosion.

题解

题意是在一维坐标轴上有$n$个怪物在$0$坐标右边。
你可以用炸弹炸任何一个位置,产生的效果是炸死这个位置的怪物(如果有的话),并且把所有在这个位置左边的怪物坐标左移$r$位,右边的怪物坐标右移$r$位,当怪物的坐标小于等于$0$时,怪物就会被陷阱杀死。
求最少用几个炸弹可以杀死所有的怪物。
因为当怪物坐标小于等于$0$的时候就会死亡,而且炸弹可以杀死当前位置的怪物。
所以我们每次炸的位置是其中一个活着的怪物的位置,并且每次炸最右边的怪物,这种方案是最优的(易证)。
奆佬请跳过下面片段
因为怪物只有两种死法,被炸死和位置小于等于$0$,因为放$n$个炸弹一定可以炸死所有怪物,所以我们要让尽量多的怪物被陷阱杀死。
因为每次炸炸弹怪物(除了被炸死的)要么往右移,要么往左移。所以不考虑炸死的情况下,让所有的怪物都往左移是最优的。
因为最多的炸弹次数取决于最右边的怪物,所以每次炸死最右边的怪物的方案最优。
证明结束
接下来我们二分答案就行了,先把所有怪物排序,判断左边数第$n-mid$个怪物能否在$mid$次导弹下被炸到陷阱里,也就是$x[mid]<=(n-mid)*r$。
注意:怪物的位置可能相同,所以输入的时候要判重。
上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include<bits/stdc++.h>
using namespace std;
int q,n,rr,x;
bool k[100009];
int ans;
int a[100009],len;
bool cmp(int x,int y){return x<y;}
int main(){
scanf("%d",&q);
while(q--){
len=0;
scanf("%d%d",&n,&rr);
for(int j=1;j<=n;j++){
scanf("%d",&x);
if(!k[x]){
k[x]=1;
a[++len]=x;
}
}
sort(a+1,a+len+1,cmp);
int l=0,r=len;
while(l<=r){
int mid=(l+r)/2;
if(a[mid]-(len-mid)*rr<=0){
ans=len-mid;
l=mid+1;
}
else r=mid-1;
}
printf("%d\n",ans);
for(int j=1;j<=len;j++)
k[a[j]]=0;
}
return 0;
}

× 请我吃糖~
打赏二维码