結果
問題 | No.5017 Tool-assisted Shooting |
ユーザー | rhoo |
提出日時 | 2023-07-20 23:54:58 |
言語 | Rust (1.77.0 + proconio) |
結果 |
AC
|
実行時間 | 1,725 ms / 2,000 ms |
コード長 | 12,461 bytes |
コンパイル時間 | 2,051 ms |
コンパイル使用メモリ | 171,040 KB |
実行使用メモリ | 24,336 KB |
スコア | 4,864,839 |
平均クエリ数 | 980.00 |
最終ジャッジ日時 | 2023-07-20 23:57:53 |
合計ジャッジ時間 | 169,536 ms |
ジャッジサーバーID (参考情報) |
judge14 / judge12 |
純コード判定しない問題か言語 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 1,540 ms
24,072 KB |
testcase_01 | AC | 1,589 ms
23,328 KB |
testcase_02 | AC | 1,501 ms
24,336 KB |
testcase_03 | AC | 1,565 ms
23,376 KB |
testcase_04 | AC | 1,622 ms
24,276 KB |
testcase_05 | AC | 1,603 ms
23,856 KB |
testcase_06 | AC | 1,585 ms
23,484 KB |
testcase_07 | AC | 1,629 ms
23,424 KB |
testcase_08 | AC | 1,581 ms
23,388 KB |
testcase_09 | AC | 1,519 ms
23,604 KB |
testcase_10 | AC | 1,612 ms
23,472 KB |
testcase_11 | AC | 1,507 ms
23,364 KB |
testcase_12 | AC | 1,519 ms
24,000 KB |
testcase_13 | AC | 1,579 ms
23,364 KB |
testcase_14 | AC | 1,627 ms
23,544 KB |
testcase_15 | AC | 1,638 ms
23,400 KB |
testcase_16 | AC | 1,600 ms
24,000 KB |
testcase_17 | AC | 1,629 ms
23,616 KB |
testcase_18 | AC | 1,659 ms
24,228 KB |
testcase_19 | AC | 1,725 ms
23,376 KB |
testcase_20 | AC | 1,602 ms
23,388 KB |
testcase_21 | AC | 1,616 ms
23,340 KB |
testcase_22 | AC | 1,496 ms
23,952 KB |
testcase_23 | AC | 1,599 ms
24,264 KB |
testcase_24 | AC | 1,574 ms
23,532 KB |
testcase_25 | AC | 1,679 ms
23,772 KB |
testcase_26 | AC | 1,525 ms
24,324 KB |
testcase_27 | AC | 1,584 ms
23,472 KB |
testcase_28 | AC | 1,665 ms
23,976 KB |
testcase_29 | AC | 1,538 ms
23,484 KB |
testcase_30 | AC | 1,577 ms
24,024 KB |
testcase_31 | AC | 1,563 ms
24,324 KB |
testcase_32 | AC | 1,568 ms
23,952 KB |
testcase_33 | AC | 1,595 ms
23,412 KB |
testcase_34 | AC | 1,560 ms
23,616 KB |
testcase_35 | AC | 1,566 ms
23,496 KB |
testcase_36 | AC | 1,545 ms
23,376 KB |
testcase_37 | AC | 1,557 ms
24,276 KB |
testcase_38 | AC | 1,631 ms
23,376 KB |
testcase_39 | AC | 1,657 ms
23,424 KB |
testcase_40 | AC | 1,595 ms
24,036 KB |
testcase_41 | AC | 1,589 ms
24,216 KB |
testcase_42 | AC | 1,629 ms
23,340 KB |
testcase_43 | AC | 1,577 ms
23,340 KB |
testcase_44 | AC | 1,588 ms
23,604 KB |
testcase_45 | AC | 1,524 ms
24,336 KB |
testcase_46 | AC | 1,598 ms
23,760 KB |
testcase_47 | AC | 1,537 ms
23,400 KB |
testcase_48 | AC | 1,574 ms
23,664 KB |
testcase_49 | AC | 1,604 ms
24,276 KB |
testcase_50 | AC | 1,612 ms
23,364 KB |
testcase_51 | AC | 1,640 ms
23,580 KB |
testcase_52 | AC | 1,639 ms
23,400 KB |
testcase_53 | AC | 1,602 ms
24,252 KB |
testcase_54 | AC | 1,551 ms
23,652 KB |
testcase_55 | AC | 1,623 ms
23,976 KB |
testcase_56 | AC | 1,584 ms
24,264 KB |
testcase_57 | AC | 1,521 ms
23,640 KB |
testcase_58 | AC | 1,606 ms
23,652 KB |
testcase_59 | AC | 1,646 ms
23,544 KB |
testcase_60 | AC | 1,602 ms
23,640 KB |
testcase_61 | AC | 1,562 ms
24,324 KB |
testcase_62 | AC | 1,553 ms
23,580 KB |
testcase_63 | AC | 1,574 ms
23,484 KB |
testcase_64 | AC | 1,639 ms
23,952 KB |
testcase_65 | AC | 1,592 ms
23,328 KB |
testcase_66 | AC | 1,644 ms
23,424 KB |
testcase_67 | AC | 1,631 ms
24,024 KB |
testcase_68 | AC | 1,526 ms
23,640 KB |
testcase_69 | AC | 1,622 ms
23,604 KB |
testcase_70 | AC | 1,580 ms
23,964 KB |
testcase_71 | AC | 1,552 ms
24,324 KB |
testcase_72 | AC | 1,571 ms
24,216 KB |
testcase_73 | AC | 1,651 ms
24,216 KB |
testcase_74 | AC | 1,603 ms
23,496 KB |
testcase_75 | AC | 1,646 ms
23,628 KB |
testcase_76 | AC | 1,612 ms
23,544 KB |
testcase_77 | AC | 1,679 ms
24,264 KB |
testcase_78 | AC | 1,625 ms
23,616 KB |
testcase_79 | AC | 1,607 ms
24,264 KB |
testcase_80 | AC | 1,640 ms
23,364 KB |
testcase_81 | AC | 1,578 ms
23,940 KB |
testcase_82 | AC | 1,551 ms
23,424 KB |
testcase_83 | AC | 1,593 ms
23,484 KB |
testcase_84 | AC | 1,577 ms
23,316 KB |
testcase_85 | AC | 1,651 ms
23,532 KB |
testcase_86 | AC | 1,571 ms
23,592 KB |
testcase_87 | AC | 1,554 ms
24,024 KB |
testcase_88 | AC | 1,638 ms
23,544 KB |
testcase_89 | AC | 1,612 ms
23,376 KB |
testcase_90 | AC | 1,642 ms
23,964 KB |
testcase_91 | AC | 1,611 ms
23,532 KB |
testcase_92 | AC | 1,566 ms
23,580 KB |
testcase_93 | AC | 1,624 ms
24,012 KB |
testcase_94 | AC | 1,566 ms
23,952 KB |
testcase_95 | AC | 1,600 ms
23,628 KB |
testcase_96 | AC | 1,637 ms
23,412 KB |
testcase_97 | AC | 1,622 ms
23,856 KB |
testcase_98 | AC | 1,597 ms
24,276 KB |
testcase_99 | AC | 1,590 ms
24,012 KB |
ソースコード
#![allow(non_snake_case)] static mut R:usize=0; #[derive(Clone,PartialEq)] struct Node{ first:u8, pos:u8, power:u32, score:u32, turn:u16, idx:[u8;W], damage:[u16;W], } impl Node{ fn next_step(&mut self,input:&Input){ for &(pos,_) in &input.idx[self.turn as usize]{ if let Some(enemy)=input.get(pos,self.idx[pos as usize] as usize){ if enemy.height<=self.turn as usize{ self.damage[pos]=0; self.idx[pos]+=1; } } } } fn isok(&self,input:&Input,pos:usize,turn:usize)->bool{ input.get(pos,self.idx[pos] as usize).map_or(true,|e|e.height-1!=turn) } fn apply(&mut self,input:&Input,op:u8)->bool{ self.pos=self.pos.apply(op); if !self.isok(input,self.pos as usize,self.turn as usize){ return false; } let level=self.power/100; let pos=self.pos as usize; if let Some(enemy)=input.get(pos,self.idx[pos] as usize){ self.damage[pos]+=level as u16; if self.damage[pos] as u32>=enemy.hp{ self.damage[pos]=0; self.idx[pos]+=1; self.score+=enemy.hp; self.power+=enemy.power; } } if !self.isok(input,self.pos as usize,self.turn as usize+1){ return false; } self.turn+=1; true } fn eval_score(&self,input:&Input)->f64{ let mut eval_score=self.score as f64; let mut eval_level=self.power as f64; let pos=self.pos as usize; if let Some(enemy)=input.get(pos,self.idx[pos] as usize){ let height=enemy.height-self.turn as usize+3; let prog=self.damage[pos] as f64/enemy.hp as f64; if self.power/100*height as u32>=enemy.hp-self.damage[pos] as u32{ let c=input.table[(prog*TABLE as f64).round() as usize]; eval_score+=enemy.hp as f64*c; eval_level+=enemy.power as f64*c; } } eval_score+eval_level*input.coef[self.turn as usize]+(rnd::next()%unsafe{R}) as f64 } fn append_cands(&self,input:&Input,cands:&mut Vec<Cand>){ let get_hash=|node:&Node,pos:usize|->u64{ input.get(pos,node.idx[pos] as usize).map_or(0,|e|e.hash*node.damage[pos] as u64) }; let hash=(0..W).map(|i|get_hash(self,i)).sum::<u64>(); for op in [!0,0,1]{ let mut node=self.clone(); let mut hash=hash; hash-=get_hash(&node,node.pos.apply(op) as usize); if !node.apply(input,op){ continue; } hash+=get_hash(&node,node.pos as usize); let cand=Cand{ eval_score:node.eval_score(input), hash:(hash^input.zob[node.pos as usize])+node.power as u64, node, }; cands.push(cand); } } } #[derive(Clone)] struct Cand{ node:Node, eval_score:f64, hash:u64, } impl Cand{ fn to_node(self)->Node{ self.node } } const MAX_WIDTH:usize=200; struct BeamSearch{ nodes:Vec<Node>, } impl BeamSearch{ fn new()->BeamSearch{ BeamSearch{ nodes:Vec::with_capacity(MAX_WIDTH), } } fn enum_cands(&self,input:&Input,cands:&mut Vec<Cand>){ for node in &self.nodes{ node.append_cands(input,cands); } } fn update<I:Iterator<Item=Cand>>(&mut self,input:&Input,cands:I){ self.nodes.clear(); for cand in cands{ let mut node=cand.to_node(); node.next_step(input); self.nodes.push(node); } } } fn solve(IO:&mut IO){ let mut solver=BeamSearch::new(); let mut set=NopHashSet::<u64>::default(); let mut cands=Vec::with_capacity(MAX_WIDTH*3); let M=170; const A0:f64=45.; const A1:f64=30.; 'a: loop{ IO.read(); solver.nodes.clear(); for op in [!0,0,1]{ let mut node=IO.state.clone(); if !node.apply(&IO.input,op){ continue; } node.first=op; solver.nodes.push(node); } for t in 0..((A0+(A1-A0)*(IO.turn as f64/TURN as f64)).round() as usize).min(TURN-IO.turn-1){ const R0:f64=10.; const R1:f64=15.; unsafe{ R=(R0+(R1-R0)*((IO.turn+t+1) as f64/TURN as f64)).round() as usize; } cands.clear(); solver.enum_cands(&IO.input,&mut cands); assert!(!cands.is_empty()); cands.sort_unstable_by_key(|cand|Reverse(O(cand.eval_score))); let mut cnt=[0;W]; let th=30; set.clear(); let it=cands.iter().filter(|cand| cnt[cand.node.pos as usize]<=th && set.insert(cand.hash) && { cnt[cand.node.pos as usize]+=1; true } ).take(M).cloned(); solver.update(&IO.input,it); let op=solver.nodes[0].first; if solver.nodes.iter().all(|node|node.first==op){ IO.write(op); continue 'a; } } IO.write(solver.nodes[0].first); } } fn main(){ let mut IO=IO::new(); solve(&mut IO) } #[derive(Clone,Copy)] struct Enemy{ hash:u64, hp:u32, power:u32, height:usize, } use std::cmp::*; const TURN:usize=1000; const H:usize=60; const W:usize=25; const TABLE:usize=65536; struct Input{ zob:[u64;W], coef:[f64;TURN+1], enemy:Vec<Vec<Enemy>>, idx:Vec<Vec<(usize,usize)>>, table:[f64;TABLE], } impl Input{ fn new()->Input{ let mut coef=[0.;TURN+1]; for i in 0..=TURN{ coef[i]=(TURN-i) as f64*5e-4/(i as f64/TURN as f64).powf(2.2); } let mut table=[0.;TABLE]; for i in 0..TABLE{ table[i]=(i as f64/TABLE as f64).powf(1.5); } Input{ zob:[();W].map(|_|hash()), coef,table, enemy:vec![vec![];W], idx:vec![vec![];TURN+H], } } fn get(&self,pos:usize,idx:usize)->Option<&Enemy>{ self.enemy[pos].get(idx) } } struct IO{ scan:Scanner, turn:usize, state:Node, input:Input, } impl IO{ fn new()->IO{ get_time(); #[allow(unused_mut)] let mut scan=Scanner::new(); #[cfg(local)]{ input!{ scan, _a:[usize;W], } } let state=Node{ first:0, pos:12, power:100, score:0, turn:0, idx:[0;W], damage:[0;W], }; IO{ scan,state, input:Input::new(), turn:0, } } fn exit(&self){ eprintln!("score = {}",self.state.score); // eprintln!("timer = {:.2}",unsafe{TIME}); eprintln!("time = {:.2}",get_time()); std::process::exit(0); } fn read(&mut self){ input!{ self.scan, n:i64, } if n==-1{ self.exit(); } input!{ self.scan, enemy:[(u32,u32,usize);n], } for (hp,power,pos) in enemy{ self.input.idx[self.turn+H].push((pos,self.input.enemy[pos].len())); let enemy=Enemy{ hp,power, height:self.turn+H, hash:hash(), }; self.input.enemy[pos].push(enemy); } } fn write(&mut self,op:u8){ match op{ u8::MAX=>println!("L"), 0=>println!("S"), 1=>println!("R"), _=>panic!(), } let f=self.state.apply(&self.input,op); assert!(f,"敵に当たってるよ"); self.state.next_step(&self.input); self.turn+=1; if self.turn==TURN{ self.exit(); } } } fn hash()->u64{ (rnd::next()+rnd::next()) as u64 } trait My{ fn apply(self,op:u8)->u8; } impl My for u8{ fn apply(self,op:u8)->u8{ (self+op+W as u8)%W as u8 } } #[macro_export]#[cfg(not(local))]macro_rules! eprint{($($_:tt)*)=>{}} #[macro_export]#[cfg(not(local))]macro_rules! eprintln{($($_:tt)*)=>{}} #[allow(unused)] fn get_time()->f64{ static mut START:f64=-1.; let time=std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs_f64(); unsafe{ if START<0.{ START=time; } #[cfg(local)]{ (time-START)*1.6 } #[cfg(not(local))]{ time-START } } } #[macro_export] macro_rules! timer{ ()=>{ let _timer=Timer(get_time()); } } static mut TIME:f64=0.; #[allow(unused)] fn time_sum()->f64{ unsafe{ TIME } } struct Timer(f64); impl Drop for Timer{ fn drop(&mut self){ unsafe{ TIME+=get_time()-self.0 } } } #[allow(unused)] mod rnd { static mut S:usize=88172645463325252; pub fn next()->usize{ unsafe{ S^=S<<13; S^=S>>7; S^=S<<17; S } } pub fn nextf()->f64{ unsafe{ std::mem::transmute::<u64,f64>((0x3ff0000000000000|next()&0xfffffffffffff) as u64)-1. } } pub fn range(a:usize,b:usize)->usize{ next()%(b-a)+a } } struct Scanner{ stack:std::str::SplitAsciiWhitespace<'static> } impl Scanner{ // fn new()->Self{ // use std::io::Read; // let mut tmp=String::new(); // std::io::stdin().read_to_string(&mut tmp).unwrap(); // Self{stack:Box::leak(tmp.into_boxed_str()).split_ascii_whitespace()} // } // fn read<T:std::str::FromStr>(&mut self)->T{ // self.stack.next().unwrap().parse::<T>().unwrap_or_else(|_|panic!("parse error {}",std::any::type_name::<T>())) // } // インタラクティブ用 fn new()->Self{ Self{stack:"".split_ascii_whitespace()} } #[track_caller] fn read<T:std::str::FromStr>(&mut self)->T{ loop{ if let Some(v)=self.stack.next(){ return v.parse::<T>().unwrap_or_else(|_|panic!("{}: parse error",std::any::type_name::<T>())); } let mut tmp=String::new(); std::io::stdin().read_line(&mut tmp).unwrap(); assert!(!tmp.is_empty()); self.stack=Box::leak(tmp.into_boxed_str()).split_ascii_whitespace(); } } } #[macro_export] macro_rules! input{ ($scan:expr $(,)?)=>{}; ($scan:expr, mut $name:ident:$t:tt $($rest:tt)*)=>{ let mut $name=read_value!($scan,$t); input!{$scan $($rest)*} }; ($scan:expr, $name:ident:$t:tt $($rest:tt)*)=>{ let $name=read_value!($scan,$t); input!{$scan $($rest)*} }; } #[macro_export] macro_rules! read_value{ ($scan:expr, ($($t:tt),*))=>{ ($(read_value!($scan, $t)),*) }; ($scan:expr, [$t:tt;$len:expr])=>{ (0..$len).map(|_|read_value!($scan,$t)).collect::<Vec<_>>() }; ($scan:expr, [$t:tt])=>{ (0..$scan.read()).map(|_|read_value!($scan,$t)).collect::<Vec<_>>() }; ($scan:expr, Chars)=>{ read_value!($scan,String).chars().collect::<Vec<char>>() }; ($scan:expr, Usize1)=>{ read_value!($scan,usize)-1 }; ($scan:expr, $t:ty)=>{ $scan.read::<$t>() }; } #[derive(PartialEq,PartialOrd)] struct O<T:PartialEq+PartialOrd>(T); impl<T:PartialEq+PartialOrd> Eq for O<T>{} impl<T:PartialEq+PartialOrd> Ord for O<T>{ fn cmp(&self,a:&O<T>)->std::cmp::Ordering{ self.0.partial_cmp(&a.0).unwrap() } } use std::collections::{HashMap,HashSet}; use core::hash::BuildHasherDefault; use core::hash::Hasher; #[derive(Default)] pub struct NopHasher{ hash:u64, } impl Hasher for NopHasher{ fn write(&mut self,_:&[u8]){ panic!(); } #[inline] fn write_u64(&mut self,n:u64){ self.hash=n; } #[inline] fn finish(&self)->u64{ self.hash } } pub type NopHashMap<K,V>=HashMap<K,V,BuildHasherDefault<NopHasher>>; pub type NopHashSet<V>=HashSet<V,BuildHasherDefault<NopHasher>>;