Problem p01353 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <algorithm>
#include <cfloat>
#include <cmath>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <string>
#include <time.h>
#include <vector>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

#define NUM 40000

struct Info {
  ll HP, attack, guard, speed;
};

struct Data {
  Data(int arg_enemy_index, ll arg_rest_count, double arg_average_damage) {
    enemy_index = arg_enemy_index;
    rest_count = arg_rest_count;
    average_damage = arg_average_damage;
  }
  bool operator<(const struct Data &arg) const {
    return average_damage < arg.average_damage;
  }
  int enemy_index;
  ll rest_count;
  double average_damage;
};

int N;
Info Hero, monster[NUM];
ll start_HP, to_hero_damage[NUM];

int main() {

  scanf("%d", &N);

  scanf("%lld %lld %lld %lld", &Hero.HP, &Hero.attack, &Hero.guard,
        &Hero.speed);
  start_HP = Hero.HP;

  ll give_damage, promised_count;

  priority_queue<Data> Q;

  for (int i = 0; i < N; i++) {
    scanf("%lld %lld %lld %lld", &monster[i].HP, &monster[i].attack,
          &monster[i].guard, &monster[i].speed);
    if (monster[i].attack <= Hero.guard) {
      continue;
    }

    to_hero_damage[i] = monster[i].attack - Hero.guard;
    give_damage = Hero.attack - monster[i].guard;

    if (monster[i].guard >= Hero.attack) {
      printf("-1\\n");
      return 0;
    }

    if (monster[i].HP % give_damage == 0) {
      promised_count = monster[i].HP / give_damage;
    } else {
      promised_count = monster[i].HP / give_damage + 1;
    }
    Q.push(Data(i, promised_count,
                (double)to_hero_damage[i] / (double)promised_count));
  }

  ll turn = 0;

  while (!Q.empty()) {

    turn += Q.top().rest_count;

    if (Hero.speed < monster[Q.top().enemy_index].speed) {
      Hero.HP -= turn * to_hero_damage[Q.top().enemy_index];
    } else {
      Hero.HP -= (turn - 1) * to_hero_damage[Q.top().enemy_index];
    }

    if (Hero.HP <= 0)
      break;

    Q.pop();
  }

  if (Hero.HP <= 0) {
    printf("-1\\n");
  } else {
    printf("%lld\\n", start_HP - Hero.HP);
  }

  return 0;
}


Error: TLE

Fixed submission:

#include <algorithm>
#include <cfloat>
#include <cmath>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <string>
#include <time.h>
#include <vector>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

#define NUM 40000

struct Info {
  ll HP, attack, guard, speed;
};

struct Data {
  Data(int arg_enemy_index, ll arg_rest_count, ll arg_promised_damage) {
    enemy_index = arg_enemy_index;
    rest_count = arg_rest_count;
    promised_damage = arg_promised_damage;
  }
  bool operator<(const struct Data &arg)
      const { // 受けることが確定したダメージの量が多い順(PQ)
    return promised_damage < arg.promised_damage;
  }
  int enemy_index;
  ll rest_count, promised_damage;
};

int N;
Info Hero, monster[NUM];
ll start_HP, to_hero_damage[NUM];

int main() {

  scanf("%d", &N);

  scanf("%lld %lld %lld %lld", &Hero.HP, &Hero.attack, &Hero.guard,
        &Hero.speed);
  start_HP = Hero.HP;

  ll give_damage, promised_count;

  priority_queue<Data> Q;
  ll to_hero_damage_sum = 0;

  for (int i = 0; i < N; i++) {
    scanf("%lld %lld %lld %lld", &monster[i].HP, &monster[i].attack,
          &monster[i].guard, &monster[i].speed);
    if (monster[i].attack <= Hero.guard) {
      continue; // 主人公にダメージを与えられないモンスターは無視
    }

    to_hero_damage[i] = monster[i].attack - Hero.guard;
    to_hero_damage_sum += to_hero_damage[i];
    give_damage = Hero.attack - monster[i].guard;

    if (monster[i].guard >=
        Hero.attack) { // 主人公が倒せない、かつ主人公にダメージに与えられるモンスターが少なくとも一匹いる場合、主人公は必ず死ぬ
      printf("-1\\n");
      return 0;
    }

    if (monster[i].speed > Hero.speed) { // 敵が先攻
      if (monster[i].HP % give_damage == 0) {
        promised_count = monster[i].HP / give_damage;
      } else {
        promised_count = monster[i].HP / give_damage + 1;
      }
    } else { // 主人公が先攻
      if (monster[i].HP % give_damage == 0) {
        promised_count = monster[i].HP / give_damage - 1;
      } else {
        promised_count = monster[i].HP / give_damage;
      }
    }
    if (promised_count > 0) {
      Q.push(Data(i, promised_count, to_hero_damage[i] * promised_count));
    }
  }

  while (!Q.empty()) {

    Hero.HP -= to_hero_damage_sum;
    if (Hero.HP <= 0)
      break;

    if (Q.top().rest_count == 1) { // このターンで敵が死んだ場合

      to_hero_damage_sum -= to_hero_damage
          [Q.top()
               .enemy_index]; // 敵が死んだので、1ターンで敵から受けるダメージの総量を減らす

      Q.pop();
      continue;
    }

    Q.push(
        Data(Q.top().enemy_index, Q.top().rest_count - 1,
             to_hero_damage[Q.top().enemy_index] * (Q.top().rest_count - 1)));

    Q.pop();
  }

  if (Hero.HP <= 0) {
    printf("-1\\n");
  } else {
    printf("%lld\\n", start_HP - Hero.HP);
  }

  return 0;
}