#![allow(non_snake_case)] struct Dij{ edge:Vec>> } impl Dij{ fn new()->Dij{ let mut edge=vec![vec![vec![];L];L]; for i in 0..L{ for j in 0..L{ let pos=P(i as i64,j as i64); for k in 0..4{ let np=pos+DD[k]; if np.in_range(){ edge[pos].push((np,1.,false)); } } } } Dij{edge} } // 一応2つのque使えばlogが消せるが、、 fn solve(&self,start:P)->Vec>{ let mut que=BinaryHeap::new(); let mut ret=vec![vec![(INFINITY,-1);L];L]; ret[start]=(0.,0); que.push(S(0.,(start,0))); while let Some(S(dist,(pos,cnt)))=que.pop(){ if ret[pos].0!=dist{ continue; } for &(np,cost,f) in &self.edge[pos]{ let nd=cost+dist; if nd(Vec,i64){ assert!(builds.len()<=T); // scoresをどうにかして計算する let mut min_dist:Vec<_>=input.data.iter().map(|&(a,b)|((a-b).abs() as f64,0)).collect(); let mut scores:Vec=vec![0]; let mut grid=Dij::new(); for &(a,b) in builds{ let edge=&mut grid.edge[a]; for i in 0..edge.len(){ if edge[i].0==b{ assert!(!edge[i].2); edge[i].1=C; edge[i].2=true; } } let edge=&mut grid.edge[b]; for i in 0..edge.len(){ if edge[i].0==a{ assert!(!edge[i].2); edge[i].1=C; edge[i].2=true; } } let dists=grid.solve(a); for (i,&(a,b)) in input.data.iter().enumerate(){ let dist=dists[a].0+dists[b].0; let cnt=dists[a].1+dists[b].1; if min_dist[i].0>dist{ min_dist[i].0=dist; min_dist[i].1=cnt; } } let score:i64=min_dist.iter().map(|(_,a)|a).sum(); scores.push(score*D); } assert_eq!(scores.len(),builds.len()+1); const INF:i64=std::i64::MAX/4; const MAX_PEOPLE:usize=101; // DP[t][i][j]:=tターンで人がi人いてjまで建設が終わっているときの最大の金 let mut dp0=vec![vec![(-INF,Rc::new(Nil));builds.len()+1];MAX_PEOPLE]; dp0[1][0].0=INIT_MONEY; for _ in 1..=T{ let mut dp1=vec![vec![(-INF,Rc::new(Nil));builds.len()+1];MAX_PEOPLE]; for j in 0..MAX_PEOPLE{ for k in 0..=builds.len(){ // 建設する if k!=builds.len() && j!=0{ let new=dp0[j][k].0-(1e7/(j as f64).sqrt()) as i64; if new>=0{ let new=new+scores[k+1]; if dp1[j][k+1].0best{ best=dp0[i][j].0; arg=dp0[i][j].1.clone(); } } } (arg.restore(),best) } fn connect(mut s:P,t:P,builds:&mut Vec<(P,P)>){ 'outer: while s!=t{ for dd in DD{ let ns=s+dd; if (s-t).abs()>(ns-t).abs(){ builds.push((s,ns)); s=ns; continue 'outer; } } panic!(); } } fn make_builds(points:&[(P,P)],rot:usize)->Vec<(P,P)>{ let mut ret=vec![]; for &(mut s,mut t) in points{ for _ in 0..rot{ s=s.rot(); t=t.rot(); } connect(s,t,&mut ret); } ret } fn solve(input:&IO)->Vec{ let a=[2,7,12]; let b=[2,5,8,11]; let mut pos=vec![vec![P(0,0);b.len()];a.len()]; for i in 0..a.len(){ for j in 0..b.len(){ pos[i][j]=P(a[i],b[j]); } } let path=vec![ (pos[1][1],pos[1][2]), (pos[1][1],pos[2][1]), (pos[1][2],pos[0][2]), (pos[2][1],pos[2][0]), (pos[0][2],pos[0][3]), (pos[2][0],pos[0][0]), (pos[0][3],pos[2][3]), ]; let mut best_ans=vec![]; let mut best=0; for i in 0..4{ let builds=make_builds(&path,i); let mut reach=vec![vec![false;L];L]; for &(s,t) in &builds{ reach[s]=true; reach[t]=true; } let mut builds=vec![]; let mut que=VecDeque::new(); que.push_back(P(7,7)); let mut reached=vec![vec![false;L];L]; while let Some(pos)=que.pop_front(){ reached[pos]=true; for dd in DD{ let np=pos+dd; if reach[np] && !reached[np]{ builds.push((pos,np)); que.push_back(np); } } } let (ans,score)=solve_dp(input,&builds); if bestIO{ let mut scan=Scanner::new(); input!{ scan, n:usize, t:usize, d:[((Usize1,Usize1),(Usize1,Usize1));N] } assert_eq!((n,t),(N,T)); let data=d.into_iter().map(|((a,b),(c,d))|(P(a as i64,b as i64),P(c as i64,d as i64))).collect::>(); IO{scan,data:data.try_into().unwrap()} } fn output(self,ans:&[Action]){ assert_eq!(ans.len(),T); let mut scan=self.scan; for &act in ans{ #[cfg(not(local))]{ input!{ scan, _u:usize, _v:usize, } } match act{ Build((P(a,b),P(c,d)))=>println!("1 {} {} {} {}",a+1,b+1,c+1,d+1), People=>println!("2"), Money=>println!("3") } } } } #[macro_export]#[cfg(not(local))]macro_rules! eprint{($($_:tt)*)=>{}} #[macro_export]#[cfg(not(local))]macro_rules! eprintln{($($_:tt)*)=>{}} 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 } } } mod rnd { static mut S:usize=88172645463325252; pub fn next()->usize{ unsafe{ S^=S<<7; S^=S>>9; S } } pub fn nextf()->f64{ f64::from_bits((0x3ff0000000000000|next()&0xfffffffffffff) as u64)-1. } pub fn range(a:usize,b:usize)->usize{ next()%(b-a)+a } } #[macro_export] macro_rules! timer{ ()=>{ let _timer=Timer(get_time()); } } static mut TIME:f64=0.; fn etime(){ unsafe{ eprintln!("{:.3}",TIME); } } struct Timer(f64); impl Drop for Timer{ fn drop(&mut self){ unsafe{ TIME+=get_time()-self.0 } } } struct Scanner{ stack:std::str::SplitAsciiWhitespace<'static> } impl Scanner{ fn new()->Self{ Self{stack:"".split_ascii_whitespace()} } fn read(&mut self)->T{ loop{ if let Some(v)=self.stack.next(){ return v.parse::().unwrap_or_else(|_|panic!("{}: parse error",std::any::type_name::())); } 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:ident, $($rest:tt)*)=>{ input_inner!{$scan,$($rest)*} }; } #[macro_export] macro_rules! input_inner{ ($scan:ident $(,)?)=>{}; ($scan:ident, $name:ident:$t:tt $($rest:tt)*)=>{ let $name=read_value!($scan,$t); input_inner!{$scan $($rest)*} }; } #[macro_export] macro_rules! read_value{ ($scan:ident, ($($t:tt),*))=>{ ($(read_value!($scan, $t)),*) }; ($scan:ident, [$t:tt;$len:expr])=>{ (0..$len).map(|_|read_value!($scan,$t)).collect::>() }; ($scan:ident, Chars)=>{ read_value!($scan,String).chars().collect::>() }; ($scan:ident, Usize1)=>{ read_value!($scan,usize)-1 }; ($scan:ident, $t:ty)=>{ $scan.read::<$t>() }; } #[derive(Clone,Copy,PartialEq,Eq,Debug,Default,Hash)] struct P(i64,i64); impl P{ fn in_range(self)->bool{ L>self.0 as usize && L>self.1 as usize } fn abs(self)->i64{ self.0.abs()+self.1.abs() } fn rot(self)->P{ P(self.1,L as i64-self.0) } } use std::ops::*; impl Add for P{ type Output=P; fn add(self,a:P)->P{ P(self.0+a.0,self.1+a.1) } } impl Sub for P{ type Output=P; fn sub(self,a:P)->P{ P(self.0-a.0,self.1-a.1) } } impl Mul for P{ type Output=P; fn mul(self,a:i64)->P{ P(self.0*a,self.1*a) } } impl Div for P{ type Output=P; fn div(self,a:i64)->P{ P(self.0/a,self.1/a) } } impl Neg for P{ type Output=P; fn neg(self)->P{ P(-self.0,-self.1) } } impl AddAssign for P{ fn add_assign(&mut self,a:P){ *self=*self+a; } } impl SubAssign for P{ fn sub_assign(&mut self,a:P){ *self=*self-a; } } impl MulAssign for P{ fn mul_assign(&mut self,a:i64){ *self=*self*a; } } impl DivAssign for P{ fn div_assign(&mut self,a:i64){ *self=*self/a; } } impl> Index

for Vec{ type Output=T::Output; fn index(&self,idx:P)->&T::Output{ &self[idx.0 as usize][idx.1 as usize] } } impl> IndexMut

for Vec{ fn index_mut(&mut self,idx:P)->&mut T::Output{ &mut self[idx.0 as usize][idx.1 as usize] } } const DD:[P;4]=[P(0,-1),P(-1,0),P(0,1),P(1,0)]; const DX:[P;8]=[P(0,-1),P(-1,-1),P(-1,0),P(-1,1),P(0,1),P(1,1),P(1,0),P(1,-1)]; use std::rc::Rc; #[derive(Clone)] enum List{ Cons{ v:T, prev:Rc> }, Nil } use List::*; impl List{ fn restore(&self)->Vec{ let mut ret=vec![]; let mut ptr=self.clone(); while let Cons{v,prev}=ptr{ ret.push(v.clone()); ptr=(*prev).clone(); } ret.reverse(); ret } } #[derive(PartialEq,PartialOrd)] struct O(T); impl Eq for O{} impl Ord for O{ fn cmp(&self,a:&O)->std::cmp::Ordering{ self.0.partial_cmp(&a.0).unwrap() } } struct S(T,U); impl PartialEq for S{ fn eq(&self,a:&S)->bool{ self.0.eq(&a.0) } } impl PartialOrd for S{ fn partial_cmp(&self,a:&S)->Option{ self.0.partial_cmp(&a.0) } } impl Eq for S{} impl Ord for S{ fn cmp(&self,a:&S)->std::cmp::Ordering{ self.partial_cmp(a).unwrap() } }