結果
| 問題 |
No.5016 Worst Mayor
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2023-04-29 16:23:48 |
| 言語 | Rust (1.83.0 + proconio) |
| 結果 |
AC
|
| 実行時間 | 1,141 ms / 2,000 ms |
| コード長 | 12,746 bytes |
| コンパイル時間 | 2,424 ms |
| コンパイル使用メモリ | 180,404 KB |
| 実行使用メモリ | 141,840 KB |
| スコア | 19,577,471,040 |
| 平均クエリ数 | 400.00 |
| 最終ジャッジ日時 | 2023-04-29 16:25:19 |
| 合計ジャッジ時間 | 60,765 ms |
|
ジャッジサーバーID (参考情報) |
judge13 / judge12 |
| 純コード判定しない問題か言語 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 50 |
コンパイルメッセージ
warning: unnecessary `unsafe` block
--> Main.rs:357:5
|
357 | unsafe{
| ^^^^^^ unnecessary `unsafe` block
|
= note: `#[warn(unused_unsafe)]` on by default
warning: function `etime` is never used
--> Main.rs:356:4
|
356 | fn etime(){
| ^^^^^
|
= note: `#[warn(dead_code)]` on by default
warning: constant `DX` is never used
--> Main.rs:510:7
|
510 | 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)];
| ^^
warning: static `S` is never used
--> Main.rs:328:16
|
328 | static mut S:usize=88172645463325252;
| ^
warning: function `next` is never used
--> Main.rs:330:12
|
330 | pub fn next()->usize{
| ^^^^
warning: function `nextf` is never used
--> Main.rs:338:12
|
338 | pub fn nextf()->f64{
| ^^^^^
warning: function `range` is never used
--> Main.rs:342:12
|
342 | pub fn range(a:usize,b:usize)->usize{
| ^^^^^
warning: 7 warnings emitted
ソースコード
#![allow(non_snake_case)]
struct Dij{
edge:Vec<Vec<Vec<(P,f64,bool)>>>
}
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<Vec<(f64,i64)>>{
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<ret[np].0{
ret[np].0=nd;
ret[np].1=cnt+f as i64;
que.push(S(nd,(np,cnt+f as i64)));
}
}
}
ret
}
}
fn solve_dp(input:&IO,builds:&[(P,P)])->(Vec<Action>,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<i64>=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].0<new{
dp1[j][k+1]=(new,Rc::new(Cons{v:Build(builds[k]),prev:dp0[j][k].1.clone()}));
}
}
}
// 協力者を集める
if j!=MAX_PEOPLE-1{
let new=dp0[j][k].0+scores[k];
if dp1[j+1][k].0<new{
dp1[j+1][k]=(dp0[j][k].0,Rc::new(Cons{v:People,prev:dp0[j][k].1.clone()}));
}
}
// 資金集めをする
let new=dp0[j][k].0+MONEY+scores[k];
if dp1[j][k].0<new{
dp1[j][k]=(new,Rc::new(Cons{v:Money,prev:dp0[j][k].1.clone()}));
}
}
}
std::mem::swap(&mut dp0,&mut dp1);
}
let mut best=0;
let mut arg=Rc::new(Nil);
for i in 0..MAX_PEOPLE{
for j in 0..=builds.len(){
if dp0[i][j].0>best{
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<Action>{
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..2{
let builds=make_builds(&path,i);
let (ans,score)=solve_dp(input,&builds);
if best<score{
best=score;
best_ans=ans;
}
}
eprintln!("score = {}",best);
let mut seen=vec![vec![false;L];L];
for &act in &best_ans{
if let Build((s,t))=act{
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!();
}
best_ans
}
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::<Vec<_>>();
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<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: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::<Vec<_>>()
};
($scan:ident, Chars)=>{
read_value!($scan,String).chars().collect::<Vec<char>>()
};
($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<i64> for P{
type Output=P;
fn mul(self,a:i64)->P{
P(self.0*a,self.1*a)
}
}
impl Div<i64> 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<i64> for P{
fn mul_assign(&mut self,a:i64){
*self=*self*a;
}
}
impl DivAssign<i64> for P{
fn div_assign(&mut self,a:i64){
*self=*self/a;
}
}
impl<T:Index<usize>> Index<P> for Vec<T>{
type Output=T::Output;
fn index(&self,idx:P)->&T::Output{
&self[idx.0 as usize][idx.1 as usize]
}
}
impl<T:IndexMut<usize>> IndexMut<P> for Vec<T>{
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<T>{
Cons{
v:T,
prev:Rc<List<T>>
},
Nil
}
use List::*;
impl<T:Clone> List<T>{
fn restore(&self)->Vec<T>{
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: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()
}
}
struct S<T:PartialEq+PartialOrd,U>(T,U);
impl<T:PartialEq+PartialOrd,U> PartialEq for S<T,U>{
fn eq(&self,a:&S<T,U>)->bool{
self.0.eq(&a.0)
}
}
impl<T:PartialEq+PartialOrd,U> PartialOrd for S<T,U>{
fn partial_cmp(&self,a:&S<T,U>)->Option<std::cmp::Ordering>{
self.0.partial_cmp(&a.0)
}
}
impl<T:PartialEq+PartialOrd,U> Eq for S<T,U>{}
impl<T:PartialEq+PartialOrd,U> Ord for S<T,U>{
fn cmp(&self,a:&S<T,U>)->std::cmp::Ordering{
self.partial_cmp(a).unwrap()
}
}