結果
問題 | No.5017 Tool-assisted Shooting |
ユーザー | poka |
提出日時 | 2023-07-29 15:04:07 |
言語 | Rust (1.77.0 + proconio) |
結果 |
AC
|
実行時間 | 126 ms / 2,000 ms |
コード長 | 8,315 bytes |
コンパイル時間 | 6,260 ms |
コンパイル使用メモリ | 154,252 KB |
実行使用メモリ | 24,444 KB |
スコア | 4,297,532 |
平均クエリ数 | 1000.00 |
最終ジャッジ日時 | 2023-07-29 15:04:30 |
合計ジャッジ時間 | 21,296 ms |
ジャッジサーバーID (参考情報) |
judge15 / judge14 |
純コード判定しない問題か言語 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 107 ms
24,336 KB |
testcase_01 | AC | 106 ms
23,616 KB |
testcase_02 | AC | 92 ms
24,036 KB |
testcase_03 | AC | 102 ms
23,604 KB |
testcase_04 | AC | 98 ms
23,544 KB |
testcase_05 | AC | 98 ms
24,408 KB |
testcase_06 | AC | 102 ms
24,060 KB |
testcase_07 | AC | 102 ms
24,012 KB |
testcase_08 | AC | 99 ms
23,616 KB |
testcase_09 | AC | 99 ms
24,432 KB |
testcase_10 | AC | 102 ms
23,544 KB |
testcase_11 | AC | 98 ms
24,192 KB |
testcase_12 | AC | 98 ms
23,340 KB |
testcase_13 | AC | 103 ms
23,496 KB |
testcase_14 | AC | 104 ms
23,952 KB |
testcase_15 | AC | 100 ms
23,400 KB |
testcase_16 | AC | 98 ms
24,348 KB |
testcase_17 | AC | 104 ms
23,808 KB |
testcase_18 | AC | 100 ms
23,952 KB |
testcase_19 | AC | 105 ms
23,388 KB |
testcase_20 | AC | 101 ms
24,192 KB |
testcase_21 | AC | 104 ms
24,264 KB |
testcase_22 | AC | 95 ms
23,532 KB |
testcase_23 | AC | 98 ms
24,036 KB |
testcase_24 | AC | 104 ms
23,352 KB |
testcase_25 | AC | 107 ms
24,012 KB |
testcase_26 | AC | 100 ms
24,444 KB |
testcase_27 | AC | 99 ms
24,336 KB |
testcase_28 | AC | 106 ms
24,012 KB |
testcase_29 | AC | 96 ms
23,676 KB |
testcase_30 | AC | 95 ms
23,340 KB |
testcase_31 | AC | 99 ms
23,532 KB |
testcase_32 | AC | 103 ms
24,396 KB |
testcase_33 | AC | 106 ms
23,832 KB |
testcase_34 | AC | 102 ms
23,376 KB |
testcase_35 | AC | 101 ms
24,000 KB |
testcase_36 | AC | 99 ms
24,024 KB |
testcase_37 | AC | 102 ms
23,952 KB |
testcase_38 | AC | 102 ms
23,424 KB |
testcase_39 | AC | 103 ms
23,964 KB |
testcase_40 | AC | 104 ms
23,412 KB |
testcase_41 | AC | 100 ms
23,808 KB |
testcase_42 | AC | 103 ms
23,664 KB |
testcase_43 | AC | 102 ms
23,988 KB |
testcase_44 | AC | 103 ms
23,352 KB |
testcase_45 | AC | 113 ms
23,640 KB |
testcase_46 | AC | 107 ms
23,604 KB |
testcase_47 | AC | 96 ms
23,988 KB |
testcase_48 | AC | 103 ms
23,604 KB |
testcase_49 | AC | 100 ms
23,640 KB |
testcase_50 | AC | 102 ms
23,424 KB |
testcase_51 | AC | 102 ms
23,388 KB |
testcase_52 | AC | 104 ms
23,808 KB |
testcase_53 | AC | 105 ms
24,228 KB |
testcase_54 | AC | 103 ms
23,616 KB |
testcase_55 | AC | 99 ms
23,580 KB |
testcase_56 | AC | 103 ms
23,652 KB |
testcase_57 | AC | 99 ms
23,340 KB |
testcase_58 | AC | 102 ms
23,832 KB |
testcase_59 | AC | 105 ms
24,000 KB |
testcase_60 | AC | 101 ms
23,388 KB |
testcase_61 | AC | 99 ms
24,060 KB |
testcase_62 | AC | 124 ms
23,412 KB |
testcase_63 | AC | 101 ms
23,664 KB |
testcase_64 | AC | 103 ms
23,424 KB |
testcase_65 | AC | 113 ms
23,628 KB |
testcase_66 | AC | 105 ms
23,340 KB |
testcase_67 | AC | 99 ms
23,412 KB |
testcase_68 | AC | 101 ms
24,432 KB |
testcase_69 | AC | 102 ms
23,604 KB |
testcase_70 | AC | 126 ms
23,820 KB |
testcase_71 | AC | 101 ms
23,796 KB |
testcase_72 | AC | 92 ms
23,364 KB |
testcase_73 | AC | 101 ms
24,180 KB |
testcase_74 | AC | 93 ms
23,640 KB |
testcase_75 | AC | 104 ms
23,496 KB |
testcase_76 | AC | 101 ms
23,388 KB |
testcase_77 | AC | 105 ms
24,372 KB |
testcase_78 | AC | 101 ms
23,520 KB |
testcase_79 | AC | 107 ms
24,024 KB |
testcase_80 | AC | 103 ms
23,520 KB |
testcase_81 | AC | 99 ms
23,496 KB |
testcase_82 | AC | 100 ms
23,424 KB |
testcase_83 | AC | 99 ms
23,436 KB |
testcase_84 | AC | 101 ms
23,604 KB |
testcase_85 | AC | 105 ms
24,012 KB |
testcase_86 | AC | 102 ms
23,388 KB |
testcase_87 | AC | 123 ms
23,664 KB |
testcase_88 | AC | 106 ms
23,988 KB |
testcase_89 | AC | 103 ms
23,400 KB |
testcase_90 | AC | 104 ms
23,844 KB |
testcase_91 | AC | 108 ms
23,796 KB |
testcase_92 | AC | 93 ms
23,628 KB |
testcase_93 | AC | 103 ms
24,264 KB |
testcase_94 | AC | 95 ms
24,324 KB |
testcase_95 | AC | 103 ms
23,664 KB |
testcase_96 | AC | 104 ms
23,676 KB |
testcase_97 | AC | 103 ms
24,312 KB |
testcase_98 | AC | 101 ms
24,024 KB |
testcase_99 | AC | 100 ms
23,676 KB |
ソースコード
use std::{collections::VecDeque, io, io::Write}; const WIDTH: usize = 25; const HEIGHT: usize = 60; const CENTER: usize = WIDTH / 2; #[allow(dead_code)] const MAX_TURN: usize = 1000; const TARGET_LEVEL: usize = 250; // 決め打ち const INF: usize = 1 << 60; // codingameから拝借 macro_rules! parse_input { ($x:expr, $t:ident) => { $x.trim().parse::<$t>().unwrap() }; } fn main() { let mut player = Player::new(); let mut enemies = vec![VecDeque::new(); WIDTH]; let mut init_hp_sums = vec![0; WIDTH]; let mut enemies_score_sums = vec![0.; WIDTH]; let mut turn = 1; while let Some(new_enemies) = read_input() { preprocess(&mut enemies, new_enemies, &mut init_hp_sums); let target_x = greedy( &player, &enemies, &mut init_hp_sums, &mut enemies_score_sums, ); let (move_success, dir) = player.move_to_target(target_x, &mut enemies); if !move_success { break; } println!("{}", dir); // flush std::io::stdout().flush().unwrap(); postprocess(&mut enemies, &mut player, &mut init_hp_sums); turn += 1; if turn > 1000 { break; } } eprintln!("{}", player.score); } fn abs_diff(a: usize, b: usize) -> usize { if a > b { a - b } else { b - a } } fn greedy( player: &Player, enemies: &Vec<VecDeque<Enemy>>, init_hp_sums: &mut Vec<usize>, enemies_score_sum: &mut Vec<f64>, ) -> usize { for i in 0..WIDTH { enemies_score_sum[i] = 0.; for j in 0..WIDTH { enemies_score_sum[i] += init_hp_sums[j] as f64 / (1 + abs_diff(i, j)).pow(2) as f64; } } let mut cand_enemies = vec![]; for i in 0..WIDTH { if !enemies[i].is_empty() { cand_enemies.push(enemies[i][0].clone()); } } let mut best_target_x = None; let mut best_value = 0.; let t = 0.15; // 決め打ち for &enemy in cand_enemies.iter() { let value = enemy.evaluation(player); let use_turn = compute_attack_turn(player, enemies, enemy.x); if use_turn == INF { continue; } // eprintln!("value: {}", value); // eprintln!("use_turn: {}", use_turn); let value = value as f64 / use_turn as f64 + enemies_score_sum[enemy.x] * t * f64::min(1., player.level as f64 / TARGET_LEVEL as f64); if best_target_x.is_none() || value > best_value { best_target_x = Some(enemy.x); best_value = value; } } // eprintln!("best_target_x: {:?}", best_target_x); if best_target_x.is_none() { // だめかもしれないがとりあえず return player.x; } else { return best_target_x.unwrap(); } } fn compute_attack_turn(player: &Player, enemies: &Vec<VecDeque<Enemy>>, target_x: usize) -> usize { let mut turn = compute_approach_turn(player, enemies, target_x); if turn == INF { return INF; } // 移動して攻撃も、移動せず攻撃も使うターンは同じ if turn > 0 { turn -= 1; } let breaking_turn = (enemies[target_x][0].now_hp + player.level - 1) / player.level; turn += breaking_turn; // 破壊までの合計ターンよりy=0に来るのがINFを返す if turn >= enemies[target_x][0].y { return INF; } turn } // 目標地点までの最短ターン数を計算する。 fn compute_approach_turn( player: &Player, enemies: &Vec<VecDeque<Enemy>>, target_x: usize, ) -> usize { let mut turn = 0; let mut player = player.clone(); let mut enemies = enemies.clone(); // preprocessとpostprocessを使う用のダミー let mut init_hp_sums = vec![INF; WIDTH]; while player.x != target_x { if turn != 0 { preprocess(&mut enemies, vec![], &mut init_hp_sums) } let (move_success, _) = player.move_to_target(target_x, &mut enemies); if !move_success { return INF; } postprocess(&mut enemies, &mut player, &mut init_hp_sums); turn += 1; } turn } fn diff_and_dir(x1: usize, x2: usize) -> (usize, char) { if x1 == x2 { return (0, 'S'); } let d1 = (x1 + WIDTH - x2) % WIDTH; let d2 = (x2 + WIDTH - x1) % WIDTH; if d1 < d2 { (d1, 'L') } else { (d2, 'R') } } fn preprocess( enemies: &mut Vec<VecDeque<Enemy>>, new_enemies: Vec<Enemy>, init_hp_sums: &mut Vec<usize>, ) { for i in 0..WIDTH { if !enemies[i].is_empty() && enemies[i][0].y == 0 { init_hp_sums[i] -= enemies[i][0].init_hp; enemies[i].pop_front(); } for enemy in enemies[i].iter_mut() { enemy.y -= 1; } } for enemy in new_enemies.into_iter() { enemies[enemy.x].push_back(enemy); init_hp_sums[enemy.x] += enemy.init_hp; } } fn postprocess( enemies: &mut Vec<VecDeque<Enemy>>, player: &mut Player, init_hp_sums: &mut Vec<usize>, ) { let x = player.x; if !enemies[x].is_empty() { if enemies[x][0].now_hp <= player.level { player.score += enemies[x][0].init_hp; player.total_power += enemies[x][0].power; player.level = 1 + player.total_power / 100; init_hp_sums[x] -= enemies[x][0].init_hp; enemies[x].pop_front(); } else { enemies[x][0].now_hp -= player.level; } } } fn read_input() -> Option<Vec<Enemy>> { let mut input_line = String::new(); io::stdin().read_line(&mut input_line).unwrap(); let n = parse_input!(input_line, i32); if n < 0 { return None; } let mut enemies = vec![]; for _ in 0..n { let mut input_line = String::new(); io::stdin().read_line(&mut input_line).unwrap(); let inputs = input_line.split(' ').collect::<Vec<_>>(); let enemy = vec![ parse_input!(inputs[0], usize), parse_input!(inputs[1], usize), parse_input!(inputs[2], usize), ]; enemies.push(Enemy::new(enemy)); } Some(enemies) } #[derive(Clone, Copy, Debug)] struct Player { x: usize, level: usize, total_power: usize, score: usize, } impl Player { fn new() -> Self { Self { x: CENTER, level: 1, total_power: 0, score: 0, } } fn move_left(&mut self) { if self.x > 0 { self.x -= 1; } else { self.x = WIDTH - 1; } } fn move_right(&mut self) { if self.x < WIDTH - 1 { self.x += 1; } else { self.x = 0; } } fn move_to_target( &mut self, target_x: usize, enemies: &mut Vec<VecDeque<Enemy>>, ) -> (bool, char) { let (_, dir) = diff_and_dir(self.x, target_x); // いけそうなら行く。駄目ならその場で待機 let mut final_dir = dir; if dir == 'R' { self.move_right(); if !enemies[self.x].is_empty() && enemies[self.x][0].y == 1 { self.move_left(); final_dir = 'S'; } } else if dir == 'L' { self.move_left(); if !enemies[self.x].is_empty() && enemies[self.x][0].y == 1 { self.move_right(); final_dir = 'S'; } } let success = enemies[self.x].is_empty() || enemies[self.x][0].y > 1; (success, final_dir) } } #[derive(Clone, Copy, Debug)] struct Enemy { init_hp: usize, now_hp: usize, power: usize, x: usize, y: usize, } impl Enemy { fn new(hpx: Vec<usize>) -> Self { let init_hp = hpx[0]; let power = hpx[1]; let x = hpx[2]; Self { init_hp, now_hp: init_hp, power, x, y: HEIGHT - 1, } } fn evaluation(&self, player: &Player) -> f64 { let t = f64::min(1.0, player.level as f64 / TARGET_LEVEL as f64); self.power as f64 * (1.0 - t) + self.init_hp as f64 * t } }