#![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 ndVec{ 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(); debug=(i,j); } } } eprintln!("best = {}",best); eprintln!("debug = {:?}",debug); arg.restore() } fn sa_path(input:&IO)->Vec

{ todo!(); } fn solve(input:&IO)->Vec{ let mut builds=vec![]; let s=4; let t=9; for i in s..t{ builds.push((P(8,i),P(8,i+1))); } builds.push((P(7,s),P(8,s))); builds.push((P(7,s),P(6,s))); builds.push((P(5,s),P(6,s))); for i in s..t{ builds.push((P(5,i),P(5,i+1))); } builds.push((P(5,t),P(4,t))); builds.push((P(3,t),P(4,t))); builds.push((P(3,t),P(2,t))); builds.push((P(8,t),P(9,t))); builds.push((P(10,t),P(9,t))); builds.push((P(10,t),P(11,t))); for i in (s..t).rev(){ builds.push((P(11,i),P(11,i+1))); } for i in (s..t).rev(){ builds.push((P(2,i),P(2,i+1))); } let mut seen=vec![vec![false;L];L]; for &(s,t) in &builds{ seen[s]=true; seen[t]=true; } eprintln!(); for i in 0..L{ for j in 0..L{ if seen[i][j]{ eprint!("#"); } else{ eprint!("."); } } eprintln!(); } solve_dp(input,&builds) } fn main(){ let IO=IO::input(); let ans=solve(&IO); IO.output(&ans); } use std::f64::INFINITY; use std::collections::BinaryHeap; #[derive(Clone,Copy,PartialEq,Eq,Debug)] enum Action{ Build((P,P)), People, Money } use Action::*; const N:usize=3000; const T:usize=400; const C:f64=0.223; const INIT_MONEY:i64=1e6 as i64; const MONEY:i64=0; const L:usize=14; const D:i64=60; struct IO{ scan:Scanner, data:[(P,P);N] } impl IO{ fn input()->IO{ 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() } } 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() } }