Atcoder F - Silver Fox vs Monster(贪心 + 差分)

折月煮酒 提交于 2020-01-27 13:22:29

题意
银狐在和怪物搏斗,怪物们站成一排,我们可以假设它们站在数轴上。第i个怪物,站在坐标XiX_i处,健康度为HH。银狐可以用炸弹攻击怪物。在坐标x处使用炸弹会降低所有怪物在坐标xDx-Dx+Dx + D(包括端点)之间的生命值。除了用炸弹降低怪物的生命值外,没有其他方法。当所有怪物的治疗为0或以下时,银狐获胜。找出获胜所需的最低炸弹数量。
思路:
贪心
按怪物出现的坐标从小到大排好序,然后每次贪心的选取第ii个怪物右侧距离为DD处设置炸弹。这样是显然正确的。然后可以记录一下右侧xi+2Dx_i+2D处位置,如果后面的怪物的xx<=xi+2D<=x_i+2D,那么相应的生命值就减去相应的伤害。
可是如果双重循环查找会超时,那可怎么办呢?
差分
设置一个差分数组q[ ]q[ \ ],每次我们贪心的选取完炸弹坐标后,可以二分查找<=xi+2D<=x_i+2D范围内最远点进行差分。
AC CodeAC \ Code

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
#define ll long long
const ll N = 2e5+10 ;
struct node{
   ll a,b;
}res[N];
bool cmp(node A,node B){
   return A.a < B.a;
}
ll q[N];
int main(){
   ios::sync_with_stdio(false); cin.tie(0);
   ll n,d,x;
   cin >> n >> d >> x;
   d <<= 1;
   for(ll i = 1;i <= n; ++i){
      cin >> res[i].a >> res[i].b;
   }
   sort(res + 1,res + n + 1,cmp);
   ll sum = 0;
   for(ll i = 1;i <= n;++ i){
      q[i] += q[i-1];
      res[i].b -= q[i] * x;
      if(res[i].b <= 0) continue;
      ll p = (res[i].b + x - 1) / x;
      sum += p;
      q[i] += p;
      ll l = i,r = n;
      ll temp = res[i].a + d;
      while(l < r){
         ll mid = l + r + 1>> 1;
         if(res[mid].a <= temp) l = mid;
         else r = mid - 1;
      }
      q[l + 1] -= p;
   }
   cout<<sum;
   
 
 
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!