結果
問題 | No.5017 Tool-assisted Shooting |
ユーザー | yunix |
提出日時 | 2023-06-30 22:36:51 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 74 ms / 2,000 ms |
コード長 | 11,371 bytes |
コンパイル時間 | 1,542 ms |
コンパイル使用メモリ | 128,544 KB |
実行使用メモリ | 24,372 KB |
スコア | 3,722,036 |
平均クエリ数 | 993.68 |
最終ジャッジ日時 | 2023-07-16 13:30:54 |
合計ジャッジ時間 | 12,285 ms |
ジャッジサーバーID (参考情報) |
judge12 / judge13 |
純コード判定しない問題か言語 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 65 ms
23,364 KB |
testcase_01 | AC | 65 ms
24,324 KB |
testcase_02 | AC | 62 ms
23,520 KB |
testcase_03 | AC | 64 ms
23,808 KB |
testcase_04 | AC | 63 ms
23,952 KB |
testcase_05 | AC | 64 ms
24,252 KB |
testcase_06 | AC | 65 ms
23,520 KB |
testcase_07 | AC | 65 ms
23,508 KB |
testcase_08 | AC | 63 ms
23,640 KB |
testcase_09 | AC | 63 ms
23,820 KB |
testcase_10 | AC | 65 ms
23,424 KB |
testcase_11 | AC | 63 ms
23,424 KB |
testcase_12 | AC | 65 ms
24,000 KB |
testcase_13 | AC | 64 ms
24,012 KB |
testcase_14 | AC | 62 ms
23,364 KB |
testcase_15 | AC | 63 ms
23,520 KB |
testcase_16 | AC | 66 ms
24,012 KB |
testcase_17 | AC | 67 ms
24,312 KB |
testcase_18 | AC | 65 ms
23,988 KB |
testcase_19 | AC | 62 ms
23,640 KB |
testcase_20 | AC | 63 ms
24,264 KB |
testcase_21 | AC | 64 ms
24,012 KB |
testcase_22 | AC | 62 ms
23,832 KB |
testcase_23 | AC | 63 ms
23,364 KB |
testcase_24 | AC | 64 ms
23,388 KB |
testcase_25 | AC | 37 ms
23,520 KB |
testcase_26 | AC | 65 ms
24,012 KB |
testcase_27 | AC | 63 ms
24,012 KB |
testcase_28 | AC | 65 ms
23,400 KB |
testcase_29 | AC | 62 ms
23,640 KB |
testcase_30 | AC | 59 ms
24,024 KB |
testcase_31 | AC | 62 ms
23,508 KB |
testcase_32 | AC | 62 ms
24,024 KB |
testcase_33 | AC | 66 ms
23,640 KB |
testcase_34 | AC | 61 ms
23,832 KB |
testcase_35 | AC | 63 ms
24,372 KB |
testcase_36 | AC | 65 ms
23,652 KB |
testcase_37 | AC | 64 ms
23,820 KB |
testcase_38 | AC | 65 ms
23,412 KB |
testcase_39 | AC | 62 ms
23,400 KB |
testcase_40 | AC | 64 ms
23,844 KB |
testcase_41 | AC | 62 ms
23,520 KB |
testcase_42 | AC | 63 ms
23,496 KB |
testcase_43 | AC | 64 ms
23,400 KB |
testcase_44 | AC | 64 ms
23,400 KB |
testcase_45 | AC | 64 ms
23,988 KB |
testcase_46 | AC | 66 ms
23,388 KB |
testcase_47 | AC | 63 ms
23,616 KB |
testcase_48 | AC | 65 ms
24,024 KB |
testcase_49 | AC | 63 ms
24,012 KB |
testcase_50 | AC | 65 ms
24,000 KB |
testcase_51 | AC | 66 ms
23,640 KB |
testcase_52 | AC | 65 ms
23,628 KB |
testcase_53 | AC | 65 ms
23,376 KB |
testcase_54 | AC | 66 ms
24,024 KB |
testcase_55 | AC | 61 ms
24,012 KB |
testcase_56 | AC | 71 ms
23,628 KB |
testcase_57 | AC | 63 ms
23,628 KB |
testcase_58 | AC | 63 ms
24,240 KB |
testcase_59 | AC | 66 ms
23,664 KB |
testcase_60 | AC | 64 ms
24,024 KB |
testcase_61 | AC | 63 ms
23,652 KB |
testcase_62 | AC | 61 ms
23,952 KB |
testcase_63 | AC | 71 ms
23,352 KB |
testcase_64 | AC | 66 ms
23,832 KB |
testcase_65 | AC | 67 ms
23,628 KB |
testcase_66 | AC | 65 ms
24,024 KB |
testcase_67 | AC | 66 ms
23,364 KB |
testcase_68 | AC | 62 ms
24,348 KB |
testcase_69 | AC | 62 ms
23,508 KB |
testcase_70 | AC | 64 ms
24,312 KB |
testcase_71 | AC | 65 ms
24,336 KB |
testcase_72 | AC | 62 ms
24,024 KB |
testcase_73 | AC | 65 ms
23,832 KB |
testcase_74 | AC | 62 ms
24,000 KB |
testcase_75 | AC | 65 ms
23,628 KB |
testcase_76 | AC | 64 ms
24,024 KB |
testcase_77 | AC | 65 ms
23,604 KB |
testcase_78 | AC | 65 ms
24,336 KB |
testcase_79 | AC | 61 ms
24,240 KB |
testcase_80 | AC | 64 ms
24,048 KB |
testcase_81 | AC | 64 ms
23,496 KB |
testcase_82 | AC | 63 ms
24,372 KB |
testcase_83 | AC | 71 ms
23,640 KB |
testcase_84 | AC | 66 ms
24,012 KB |
testcase_85 | AC | 66 ms
23,520 KB |
testcase_86 | AC | 64 ms
23,640 KB |
testcase_87 | AC | 64 ms
24,000 KB |
testcase_88 | AC | 63 ms
24,240 KB |
testcase_89 | AC | 63 ms
24,024 KB |
testcase_90 | AC | 66 ms
24,360 KB |
testcase_91 | AC | 66 ms
24,240 KB |
testcase_92 | AC | 62 ms
24,336 KB |
testcase_93 | AC | 63 ms
24,336 KB |
testcase_94 | AC | 63 ms
23,388 KB |
testcase_95 | AC | 71 ms
24,024 KB |
testcase_96 | AC | 74 ms
24,360 KB |
testcase_97 | AC | 64 ms
23,400 KB |
testcase_98 | AC | 64 ms
24,024 KB |
testcase_99 | AC | 63 ms
23,352 KB |
コンパイルメッセージ
main.cpp: メンバ関数 ‘char GreedyCommander::check_die(char)’ 内: main.cpp:425:17: 警告: ‘dx’ may be used uninitialized [-Wmaybe-uninitialized] 425 | if (can_move(dx)) | ~~~~~~~~^~~~ main.cpp:411:9: 備考: ‘dx’ はここで定義されています 411 | int dx; | ^~
ソースコード
#include <iostream> #include <string> #include <vector> #include <tuple> #include <chrono> #include <algorithm> #include <random> #include <map> #include <set> #include <queue> #include <random> #include <chrono> #include <cmath> #include <climits> #include <bitset> #include <time.h> using namespace std; using Ps = pair<short, short>; using vec_int = vector<int>; using P = pair<int, int>; using P2 = pair<P, P>; using P3 = pair<float, int>; using T = tuple<int, int, int>; using T2 = tuple<float, int, int>; using T3 = tuple<float, int, int, int, int>; using T4 = tuple<int, int, int, int>; using T5 = tuple<int, int, int, int, int>; using TT = tuple<int, int, int>; using ll = long long; using uc = unsigned char; #define rep(i, n) for (int i = 0; i < (int)(n); i++) // #pragma GCC optimize("Ofast") std::mt19937 mt{12345}; int RAND_ARR_LEN = 100000; int RAND_RANGE = 1000000000; float TIME_LIMIT = 5000; float INV_TIME_LIMIT = 1. / 1000.; const int JOB_MAX_LEN = 1003; std::uniform_int_distribution<int> dist(1, RAND_RANGE); int WAITING_TASK = 1001; void remove_val_and_pop_from_last(vec_int &A, int val) { for (int i = 0; i < A.size(); i++) { if (A.at(i) == val) { A.at(i) = A.at(A.size() - 1); A.pop_back(); return; } } throw runtime_error("trying to remove non-existing value"); } class Rand { private: int count = 0; vec_int rand_arr; public: Rand(){ rep(i, RAND_ARR_LEN){ rand_arr.push_back(dist(mt)); } } ; int get(); int get_rand(int from, int to); float get_float(); } ; int Rand::get() { int num = rand_arr.at(count); count += 1; count %= RAND_ARR_LEN; return num; } int Rand::get_rand(int from, int to) { int diff = to - from; int num = get() % diff; return num + from; } float Rand::get_float() { // 0~1の間の一様乱数 return (float)get() / (float)RAND_RANGE; } Rand ro; class PseudoSet { private: vec_int index_arr; public: vec_int data; PseudoSet(){}; PseudoSet(int value_range) { index_arr = vec_int(value_range, -1); } bool count(int value); void insert(int value); void erase(int value); vec_int get_data() { return data; }; int size() { return data.size(); }; int get_random() { return data.at(ro.get_rand(0, size())); }; }; bool PseudoSet::count(int value) { return index_arr[value] != -1; } void PseudoSet::insert(int value) { if (count(value)) return; index_arr[value] = data.size(); data.push_back(value); } void PseudoSet::erase(int value) { if (!count(value)) { // throw runtime_error("no existing value:"+to_string(value)); return; } int tail_value = data[data.size() - 1]; if (value == tail_value) { data.pop_back(); index_arr[value] = -1; } else { index_arr[tail_value] = index_arr[value]; index_arr[value] = -1; data[index_arr[tail_value]] = tail_value; data.pop_back(); } } float get_time(bool init) { static std::chrono::system_clock::time_point start; if (init) { start = std::chrono::system_clock::now(); } std::chrono::system_clock::time_point end = std::chrono::system_clock::now(); return std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); // 処理に要した時間をミリ秒に変換 } double current_tmp(double current_time, double T0, double T1) { return T1 + (T0 - T1) * (TIME_LIMIT * 0.92 - current_time) / (TIME_LIMIT * 0.92); // double start_time = TIME_LIMIT * 0.6; // double x = (current_time - start_time) / (TIME_LIMIT * 0.32); // return pow(T1, 1 - x) + (T0, x); } bool is_valid_transition(int diff, double current_time, double T0, float T1) { float t = current_tmp(current_time, T0, T1); float rand = ro.get_float(); // diffが正だったら常にアクセぷと return rand < exp(((float)diff) / t); } struct Enemy { int max_HP; int HP; int power; int x; int y; }; class Game { private: PseudoSet alive_enemies; vector<deque<int>> enemy_queue; public: int earned_power; int turn; int score; int x_pos; Game(); void move(char command); void attack(); void pop_enemies(int n); void process_turn(); bool is_game_over(); bool is_alive(int enemy_index) { return enemies[enemy_index].HP > 0 && turn <= enemies[enemy_index].y; } int get_enemy_index(int x); vector<Enemy> enemies; bool can_kill_enemy(int enemy_ind, int turns); }; Game::Game() { turn = 0; x_pos = 12; earned_power = 0; score = 0; enemy_queue = vector<deque<int>>(25); } void Game::pop_enemies(int n) { vec_int h(n), p(n), x(n); rep(i, n) cin >> h.at(i) >> p.at(i) >> x.at(i); for (int i = 0; i < n; i++) { enemies.push_back(Enemy{h.at(i), h.at(i), p.at(i), x.at(i), 59 + turn}); enemy_queue.at(x.at(i)).push_back(enemies.size() - 1); } } bool Game::is_game_over() { int enemy_ind = get_enemy_index(x_pos); if (turn == 368) { cerr << "enemy_ind:" << enemy_ind << " " << enemies[enemy_ind].y << " " << enemies[enemy_ind].HP << endl; } if (enemy_ind == -1) return false; if (enemies[enemy_ind].y == turn && enemies[enemy_ind].HP > 0) return true; return false; } void Game::move(char command) { switch (command) { case 'L': x_pos--; break; case 'R': x_pos++; break; case 'S': break; default: throw runtime_error("invalid command"); } cout << command << endl; } void Game::attack() { int enemy_ind = get_enemy_index(x_pos); if (enemy_ind == -1) return; // 敵が見つかった int my_power = 1 + earned_power / 100; // 攻撃 enemies.at(enemy_ind).HP = max(0, enemies.at(enemy_ind).HP - my_power); // 敵が死んだ if (enemies.at(enemy_ind).HP == 0) { earned_power += enemies.at(enemy_ind).power; my_power += enemies.at(enemy_ind).power; score += enemies.at(enemy_ind).max_HP; enemy_queue.at(x_pos).pop_front(); } } void Game::process_turn() { turn++; } int Game::get_enemy_index(int x) { while (!enemy_queue.at(x).empty()) { int ind = enemy_queue.at(x).front(); if (enemies.at(ind).y < turn) { enemy_queue.at(x).pop_front(); continue; } return ind; } return -1; } bool Game::can_kill_enemy(int enemy_ind, int turns) { int diff = enemies[enemy_ind].y - turn; return diff > turns; } struct GreedyCommander { private: Game *game; int target_enemy; int find_target(); bool will_die(); public: GreedyCommander(Game *game) : game(game) { target_enemy = -1; }; char get_command(); bool can_move(int dx); char check_die(char command); }; int GreedyCommander::find_target() { int x = game->x_pos; int current_power = game->earned_power / 100 + 1; double best_efficiency = 0; double best_enemy = -1; for (int i = max(0, x - 8); i <= min(24, x + 8); i++) { int enemy_ind = game->get_enemy_index(i); if (enemy_ind == -1) continue; int res_HP = game->enemies[enemy_ind].HP; int turns = max(abs(x - i) - 1, 0) + res_HP / current_power; if (res_HP % current_power != 0) turns++; // cerr << "turns:" << turns << " enemy:" << enemy_ind << endl; if (!game->can_kill_enemy(enemy_ind, turns)) continue; // int power = game->enemies[enemy_ind].power; int sc; if (game->turn >= 500) { sc = game->enemies[enemy_ind].max_HP; } else { sc = game->enemies[enemy_ind].power; } double eff = (double)sc / (double)turns; // cerr << i << " " << eff << " " << enemy_ind << " " << game->turn << endl; if (eff > best_efficiency) { best_efficiency = eff; best_enemy = enemy_ind; } } return best_enemy; } bool GreedyCommander::can_move(int dx) { int x = game->x_pos + dx; if (x < 0 || x >= 25) return false; int enemy_index = game->get_enemy_index(x); if (enemy_index == -1) return true; int y = game->enemies[enemy_index].y; if (y == game->turn || y == game->turn + 1) return false; return true; } char GreedyCommander::check_die(char command) { int dx; switch (command) { case 'R': dx = 1; break; case 'L': dx = -1; break; case 'S': dx = 0; break; } if (can_move(dx)) { return command; } for (int dx2 = -1; dx2 <= 1; dx2++) { if (dx2 == dx) continue; if (can_move(dx2)) { switch (dx2) { case -1: return 'L'; case 0: return 'S'; case 1: return 'R'; } } } cerr << "command:" << command << " x:" << game->x_pos << endl; int enemy_ind = game->get_enemy_index(game->x_pos + dx); cerr << game->turn << " " << game->enemies[enemy_ind].y << endl; // 諦める return command; } char GreedyCommander::get_command() { if (target_enemy == -1 || !game->is_alive(target_enemy)) { target_enemy = find_target(); } char command; if (target_enemy == -1) { command = 'S'; } else { int enemy_x = game->enemies[target_enemy].x; if (enemy_x == game->x_pos) { command = 'S'; } else if (enemy_x < game->x_pos) { command = 'L'; } else { command = 'R'; } /* if (game->turn < 560 && game->turn > 550) { cerr << target_enemy << " " << enemy_x << " " << command << " " << game->turn << endl; cerr << game->enemies[target_enemy].y << " " << game->enemies[target_enemy].HP << endl; } */ } command = check_die(command); /* if (game->turn < 560 && game->turn > 550) { cerr << "after check:" << command << endl; } */ return command; } double T0 = 500.; double T1 = 0; int main(int argc, char *argv[]) { #ifdef LOCAL vec_int pp; rep(i, 25) { int val; cin >> val; pp.push_back(val); } #endif #ifdef OPTUNA_STUDY cerr << "optuna study, override parameters" << endl; T0 = stod(argv[1]); T1 = stod(argv[2]); #endif get_time(true); Game game = Game(); GreedyCommander commander = GreedyCommander(&game); rep(i, 1000) { game.process_turn(); if (game.is_game_over()) break; int n; cin >> n; if (n == -1) break; game.pop_enemies(n); char command = commander.get_command(); game.move(command); if (game.is_game_over()) break; game.attack(); } cerr << " turn:" << game.turn << " power:" << game.earned_power << " score:" << game.score << endl; return 0; }