提出 #63393965
ソースコード 拡げる
use std::{
cmp::Reverse,
collections::{BinaryHeap, HashSet, VecDeque},
hash::{BuildHasherDefault, Hasher},
process::exit,
};
use itertools::Itertools;
use proconio::input;
use rand::{Rng, SeedableRng};
use rand_pcg::Pcg64Mcg;
const TIME_LIMIT_SEC: f64 = 1.95;
const N: usize = 20;
const M_MAX: usize = 3;
const UDLR: [char; 4] = ['U', 'D', 'L', 'R'];
const DXDY: [(usize, usize); 4] = [(usize::MAX, 0), (1, 0), (0, usize::MAX), (0, 1)];
const WARN_TIME_SEC: f64 = 0.75 * TIME_LIMIT_SEC;
const A: u8 = 3;
const B: u8 = 4;
const C: u8 = 5;
const WALL: u8 = 6;
const ROCK: u8 = 7;
const EMPTY: u8 = 8;
const FALL_BONUS: Cost = 30;
const DIST_MIN_W: Cost = 16; // A: 16, B: 12, C: 14
const DIST_MAX_W: Cost = 1;
const ROCK_CROSS_W: Cost = 5;
const ROCK_W: Cost = 70;
const STD_W: f64 = 50.0; // A: 50.0, B: 25.0, C: 40.0
fn main() {
get_time_sec();
let input = Input::read();
let config = Config {
max_turn: 10000,
beam_width: 18000,
tour_capacity: 1 << 16,
hash_que_turn: 8,
};
let state = State::new(&input);
let actions = beam_search(&config, state);
for action in actions {
let op = match action.op {
Op::Move => 1,
Op::Carry => 2,
Op::Roll => 3,
Op::Nop => unreachable!(),
};
println!("{} {}", op, UDLR[action.dir as usize]);
}
exit(0);
}
fn char_to_u8(c: char) -> u8 {
match c {
'a' => 0,
'b' => 1,
'c' => 2,
'A' => A,
'B' => B,
'C' => C,
'#' => WALL,
'@' => ROCK,
'.' => EMPTY,
_ => unreachable!(),
}
}
fn is_hole_or_wall(c: u8) -> bool {
3 <= c && c <= 6
}
type Cost = i32;
type Hash = u64;
// beam search setting
// capacity = 0 is OK.
#[derive(Debug, Clone)]
pub struct Config {
max_turn: usize,
beam_width: usize,
tour_capacity: usize,
hash_que_turn: usize,
}
#[derive(Debug, Clone, PartialEq, Eq)]
enum Op {
Move,
Carry,
Roll,
Nop,
}
// data for a state transition
// Try to minimize memory usage.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Action {
x: u8,
y: u8,
op: Op,
dir: u8,
bx: u8, // block x
by: u8, // block y
}
impl Action {
fn next_pos(&self) -> (usize, usize) {
match self.op {
Op::Move | Op::Carry => {
let (dx, dy) = DXDY[self.dir as usize];
let x = (self.x as usize).wrapping_add(dx);
let y = (self.y as usize).wrapping_add(dy);
(x, y)
}
_ => (self.x as usize, self.y as usize),
}
}
}
// data for an expansion node
#[derive(Debug, Clone)]
struct Candidate {
action: Action,
cost: Cost,
hash: Hash,
parent: u32,
}
// erasable max priority queue
#[derive(Debug, Clone)]
struct SegmentTree {
n: usize,
log: usize,
size: usize,
d: Vec<(Cost, usize)>,
}
impl SegmentTree {
fn new(n: usize) -> Self {
let mut ret = Self {
n: 0,
log: 0,
size: 0,
d: Vec::new(),
};
ret.init(n);
ret
}
fn init(&mut self, n: usize) {
self.n = n;
self.size = n.next_power_of_two();
self.log = self.size.trailing_zeros() as usize;
self.d.clear();
self.d.resize(2 * self.size, (Cost::MIN, usize::MAX));
}
fn build(&mut self, candidates: &Vec<Candidate>) {
self.init(candidates.len());
for i in 0..self.n {
self.d[self.size + i] = (candidates[i].cost, i);
}
for i in (1..self.size).rev() {
self.update(i);
}
}
fn set(&mut self, p: usize, cost: Cost) {
debug_assert!(p < self.n);
let q = p + self.size;
self.d[q] = (cost, p);
for i in 1..=self.log {
self.update(q >> i);
}
}
fn top(&self) -> (Cost, usize) {
self.d[1]
}
fn update(&mut self, k: usize) {
let (c0, p0) = self.d[2 * k];
let (c1, p1) = self.d[2 * k + 1];
self.d[k] = if c0 >= c1 { (c0, p0) } else { (c1, p1) };
}
}
// select beam width candidates from better evaluation
// It remains only the best one for same hash candidates.
#[derive(Debug, Clone)]
struct Selector {
beam_width: usize,
max_beam_width: usize,
hash_que_size: usize,
candidates: Vec<Candidate>,
hashes: NoHashSet,
hash_que: VecDeque<Hash>,
segtree: SegmentTree,
finished_candidate: Option<Candidate>,
}
impl Selector {
fn new(beam_width: usize, hash_que_turn: usize) -> Self {
let hash_que_size = beam_width * hash_que_turn;
Self {
beam_width,
max_beam_width: beam_width,
hash_que_size,
candidates: Vec::with_capacity(beam_width),
hashes: NoHashSet::default(),
hash_que: VecDeque::with_capacity(hash_que_size),
segtree: SegmentTree::new(beam_width),
finished_candidate: None,
}
}
// add a candidate
// finished = true iff it can get feasible solution through the candidate in the turn minimizing problem.
// It returns true iff it provisionally accept the candidate.
#[inline(always)]
fn push(&mut self, candidate: Candidate, finished: bool) -> bool {
let cost = candidate.cost;
if finished {
self.finished_candidate = Some(candidate);
return true;
}
if self.built_segtree() && cost >= self.segtree.top().0 {
return false;
}
let hash = candidate.hash;
if !self.hashes.insert(hash) {
return false;
}
self.hash_que.push_back(hash);
if self.built_segtree() {
let p = self.segtree.top().1;
self.candidates[p] = candidate;
self.segtree.set(p, cost);
} else {
self.candidates.push(candidate);
if self.built_segtree() {
// candidates become full
self.segtree.build(&self.candidates);
}
}
true
}
fn clear(&mut self) {
self.candidates.clear();
self.finished_candidate = None;
for _ in self.hash_que_size..self.hash_que.len() {
let hash = self.hash_que.pop_front().unwrap();
self.hashes.remove(&hash);
}
if get_time_sec() > WARN_TIME_SEC {
self.beam_width = self.max_beam_width / 2;
}
}
fn built_segtree(&self) -> bool {
self.candidates.len() == self.beam_width
}
}
#[derive(Debug, Clone)]
pub struct State {
num_ore_type: usize,
holes: [(usize, usize); M_MAX],
hashes: [[Hash; N + 2]; N + 2],
dists: [[[Cost; N + 2]; N + 2]; M_MAX],
grid: [[u8; N + 2]; N + 2],
num_ore: usize,
x_sum: usize,
x2_sum: usize,
y_sum: usize,
y2_sum: usize,
}
// data updated in depth first search
impl State {
pub fn new(input: &Input) -> Self {
let mut rng = Pcg64Mcg::seed_from_u64(0);
let mut hashes = [[0; N + 2]; N + 2];
for x in 1..=N {
for y in 1..=N {
hashes[x][y] = rng.gen();
}
}
let mut ret = Self {
num_ore_type: input.num_ore_type,
holes: input.holes,
hashes,
dists: [[[Cost::MAX; N + 2]; N + 2]; M_MAX],
grid: input.grid,
num_ore: 0,
x_sum: 0,
x2_sum: 0,
y_sum: 0,
y2_sum: 0,
};
ret.init_dists();
ret.init_sum();
ret
}
fn init_sum(&mut self) {
for x in 1..=N {
for y in 1..=N {
let gxy = self.grid[x][y] as usize;
if gxy < M_MAX {
self.num_ore += 1;
self.x_sum += x;
self.x2_sum += x * x;
self.y_sum += y;
self.y2_sum += y * y;
}
}
}
}
fn init_dists(&mut self) {
let mut que = BinaryHeap::new();
for ore in 0..self.num_ore_type {
loop {
self.dists[ore] = [[Cost::MAX; N + 2]; N + 2];
let mut preds = [[(usize::MAX, usize::MAX); N + 2]; N + 2];
let (sx, sy) = self.holes[ore];
self.dists[ore][sx][sy] = 0;
for (dx, dy) in DXDY {
let mut x = sx.wrapping_add(dx);
let mut y = sy.wrapping_add(dy);
let mut dist = FALL_BONUS + DIST_MAX_W;
loop {
if is_hole_or_wall(self.grid[x][y]) {
break;
}
if self.grid[x][y] == ROCK {
dist += ROCK_CROSS_W;
}
self.dists[ore][x][y] = dist;
preds[x][y] = (x.wrapping_sub(dx), y.wrapping_sub(dy));
que.push((Reverse(dist), x, y));
x = x.wrapping_add(dx);
y = y.wrapping_add(dy);
dist += DIST_MAX_W;
}
}
// Dijkstra
let mut update_rock = false;
while let Some((Reverse(dist), x, y)) = que.pop() {
if self.dists[ore][x][y] < dist {
continue;
}
if self.grid[x][y] < M_MAX as u8 {
// restore path
let mut px = x;
let mut py = y;
while px != sx || py != sy {
let (qx, qy) = preds[px][py];
if self.grid[qx][qy] == ROCK {
// convert rock to ore
self.grid[qx][qy] = ore as u8;
update_rock = true;
}
px = qx;
py = qy;
}
}
for (dx, dy) in DXDY {
let nx = x.wrapping_add(dx);
let ny = y.wrapping_add(dy);
if is_hole_or_wall(self.grid[nx][ny]) {
continue;
}
let mut ndist = dist + DIST_MIN_W;
if self.grid[nx][ny] == ROCK {
ndist += ROCK_W;
}
if self.dists[ore][nx][ny].chmin(ndist) {
preds[nx][ny] = (x, y);
que.push((Reverse(ndist), nx, ny));
}
}
}
if !update_rock {
break;
}
}
}
}
fn calc_std_cost(&self, num_ore: usize, x_sum: usize, x2_sum: usize, y_sum: usize, y2_sum: usize) -> Cost {
if num_ore == 0 {
return 0;
}
let x_var = x2_sum as f64 / num_ore as f64 - (x_sum as f64 / num_ore as f64).powi(2);
let x_std = x_var.sqrt();
let y_var = y2_sum as f64 / num_ore as f64 - (y_sum as f64 / num_ore as f64).powi(2);
let y_std = y_var.sqrt();
((x_std + y_std) * STD_W) as i32
}
// return the initial value of Evaluator and Hash
fn get_initial_data(&self) -> (Cost, Action, Hash) {
let mut cost = self.calc_std_cost(self.num_ore, self.x_sum, self.x2_sum, self.y_sum, self.y2_sum);
let mut hash = 0;
for x in 1..=N {
for y in 1..=N {
let gxy = self.grid[x][y] as usize;
if gxy >= M_MAX {
continue;
}
cost += self.dists[gxy][x][y];
hash ^= self.hashes[x][y];
}
}
let (sx, sy) = self.holes[0];
hash ^= self.hashes[sx][sy] >> 1;
let action = Action {
x: sx as u8,
y: sy as u8,
op: Op::Nop,
dir: 0,
bx: 0,
by: 0,
};
(cost, action, hash)
}
// add candidates to selector
// argument
// - evaluator: current evaluator
// - action: action to move to current state
// - hash: current hash
// - parent: current node ID (parent node ID for next state)
fn expand(
&self,
cost: Cost,
action: &Action,
mut hash: Hash,
parent: u32,
selector: &mut Selector,
) {
let (px, py) = action.next_pos();
hash ^= self.hashes[px][py] >> 1;
// move
for dir in 0..4 {
let (dx, dy) = DXDY[dir];
let nx = px.wrapping_add(dx);
let ny = py.wrapping_add(dy);
let gn = self.grid[nx][ny];
if gn == WALL {
continue;
}
let naction = Action {
x: px as u8,
y: py as u8,
op: Op::Move,
dir: dir as u8,
bx: 0,
by: 0,
};
let candidate = Candidate {
action: naction,
cost,
hash: hash ^ (self.hashes[nx][ny] >> 1),
parent,
};
selector.push(candidate, false);
}
let gp = self.grid[px][py] as usize;
if gp >= M_MAX {
// cannot pick up ore
return;
}
let cost = cost - self.calc_std_cost(self.num_ore, self.x_sum, self.x2_sum, self.y_sum, self.y2_sum);
let x_sum = self.x_sum - px;
let x2_sum = self.x2_sum - px * px;
let y_sum = self.y_sum - py;
let y2_sum = self.y2_sum - py * py;
// carry
for dir in 0..4 {
let (dx, dy) = DXDY[dir];
let bx = px.wrapping_add(dx);
let by = py.wrapping_add(dy);
let gb = self.grid[bx][by] as usize;
if gb != EMPTY as usize && gb != gp + M_MAX {
continue;
}
let naction = Action {
x: px as u8,
y: py as u8,
op: Op::Carry,
dir: dir as u8,
bx: bx as u8,
by: by as u8,
};
let mut ncost = cost;
let mut nhash = hash ^ (self.hashes[bx][by] >> 1);
ncost -= self.dists[gp][px][py];
nhash ^= self.hashes[px][py];
if gb == EMPTY as usize {
ncost += self.dists[gp][bx][by];
nhash ^= self.hashes[bx][by];
ncost += self.calc_std_cost(self.num_ore, x_sum + bx, x2_sum + bx * bx, y_sum + by, y2_sum + by * by);
} else {
ncost += self.calc_std_cost(self.num_ore - 1, x_sum, x2_sum, y_sum, y2_sum);
}
let finished = ncost == 0;
if finished {
debug_assert_eq!(nhash, self.hashes[bx][by] >> 1);
}
let candidate = Candidate {
action: naction,
cost: ncost,
hash: nhash,
parent,
};
selector.push(candidate, finished);
}
// roll
hash ^= self.hashes[px][py] >> 1;
for dir in 0..4 {
let (bx, by) = self.roll_ore(px, py, gp, dir);
if bx == px && by == py {
continue;
}
let naction = Action {
x: px as u8,
y: py as u8,
op: Op::Roll,
dir: dir as u8,
bx: bx as u8,
by: by as u8,
};
let mut ncost = cost;
let mut nhash = hash;
ncost -= self.dists[gp][px][py];
nhash ^= self.hashes[px][py];
if self.grid[bx][by] == EMPTY {
ncost += self.dists[gp][bx][by];
nhash ^= self.hashes[bx][by];
ncost += self.calc_std_cost(self.num_ore, x_sum + bx, x2_sum + bx * bx, y_sum + by, y2_sum + by * by);
} else {
ncost += self.calc_std_cost(self.num_ore - 1, x_sum, x2_sum, y_sum, y2_sum);
}
let finished = ncost == 0;
if finished {
debug_assert_eq!(nhash, self.hashes[px][py] >> 1);
}
let candidate = Candidate {
action: naction,
cost: ncost,
hash: nhash,
parent,
};
selector.push(candidate, finished);
}
}
fn roll_ore(&self, sx: usize, sy: usize, g: usize, dir: usize) -> (usize, usize) {
let (dx, dy) = DXDY[dir];
let mut x = sx;
let mut y = sy;
loop {
let nx = x.wrapping_add(dx);
let ny = y.wrapping_add(dy);
let gn = self.grid[nx][ny];
if gn == EMPTY {
x = nx;
y = ny;
} else if gn as usize == g + M_MAX {
// drop ore to correct hole
return (nx, ny);
} else if A <= gn && gn <= C {
// drop ore to wrong hole
return (sx, sy);
} else {
// collide
return (x, y);
}
}
}
fn move_forward(&mut self, action: &Action) {
// update grid
match action.op {
Op::Carry | Op::Roll => {
let px = action.x as usize;
let py = action.y as usize;
let gp = self.grid[px][py] as usize;
debug_assert!(gp < M_MAX);
self.grid[px][py] = EMPTY;
self.x_sum -= px;
self.x2_sum -= px * px;
self.y_sum -= py;
self.y2_sum -= py * py;
let bx = action.bx as usize;
let by = action.by as usize;
let gbx = self.grid[bx][by] as usize;
if gbx == gp + M_MAX {
// drop ore to hole
self.num_ore -= 1;
} else {
debug_assert_eq!(gbx, EMPTY as usize);
self.grid[bx][by] = gp as u8;
self.x_sum += bx;
self.x2_sum += bx * bx;
self.y_sum += by;
self.y2_sum += by * by;
}
}
_ => (),
}
}
fn move_backward(&mut self, action: &Action) {
// update grid
match action.op {
Op::Carry | Op::Roll => {
let px = action.x as usize;
let py = action.y as usize;
debug_assert_eq!(self.grid[px][py], EMPTY);
self.x_sum += px;
self.x2_sum += px * px;
self.y_sum += py;
self.y2_sum += py * py;
let bx = action.bx as usize;
let by = action.by as usize;
let gbx = self.grid[bx][by] as usize;
if gbx < M_MAX {
self.grid[px][py] = gbx as u8;
self.grid[bx][by] = EMPTY;
self.x_sum -= bx;
self.x2_sum -= bx * bx;
self.y_sum -= by;
self.y2_sum -= by * by;
} else {
// pick up ore from hole
debug_assert!(gbx < 2 * M_MAX);
self.grid[px][py] = (gbx - M_MAX) as u8;
self.num_ore += 1;
}
}
_ => (),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
enum EdgeProperty {
Leaf,
Forward,
Backward,
}
#[derive(Debug, Clone)]
struct Edge {
property: EdgeProperty,
action: Action,
}
#[derive(Debug, Clone)]
struct Tree {
state: State,
curr_tour: Vec<Edge>,
next_tour: Vec<Edge>,
leaves: Vec<(Cost, Hash)>,
buckets: Vec<Vec<(Action, Cost, Hash)>>,
direct_road: Vec<Action>,
}
impl Tree {
fn new(state: State, config: &Config) -> Self {
Self {
state,
curr_tour: Vec::with_capacity(config.tour_capacity),
next_tour: Vec::with_capacity(config.tour_capacity),
leaves: Vec::with_capacity(config.beam_width as usize),
buckets: vec![vec![]; config.beam_width as usize],
direct_road: Vec::new(),
}
}
// add candidates to selector while updating state
fn dfs(&mut self, selector: &mut Selector) {
if self.curr_tour.is_empty() {
// the first turn
let (cost, action, hash) = self.state.get_initial_data();
self.state.expand(cost, &action, hash, 0, selector);
return;
}
let mut leaf_id = 0;
for edge in &self.curr_tour {
match edge.property {
EdgeProperty::Leaf => {
let (cost, hash) = self.leaves[leaf_id];
self.state.move_forward(&edge.action);
self.state
.expand(cost, &edge.action, hash, leaf_id as u32, selector);
self.state.move_backward(&edge.action);
leaf_id += 1;
}
EdgeProperty::Forward => self.state.move_forward(&edge.action),
EdgeProperty::Backward => self.state.move_backward(&edge.action),
}
}
}
// add new nodes and remove useless nodes
fn update(&mut self, candidates: &Vec<Candidate>) {
self.leaves.clear();
if self.curr_tour.is_empty() {
// no branch
self.curr_tour.clear();
for candidate in candidates {
self.curr_tour.push(Edge {
property: EdgeProperty::Leaf,
action: candidate.action.clone(),
});
self.leaves.push((candidate.cost, candidate.hash));
}
return;
}
// bucket sort
for candidate in candidates {
self.buckets[candidate.parent as usize].push((
candidate.action.clone(),
candidate.cost,
candidate.hash,
));
}
let mut curr_tour_id = 0;
// do not repeat direct road
let is_direct_road = |curr_tour_id: usize, curr_tour: &Vec<Edge>| {
curr_tour[curr_tour_id].property == EdgeProperty::Forward
&& curr_tour.last().unwrap().action == curr_tour[curr_tour_id].action
};
while is_direct_road(curr_tour_id, &self.curr_tour) {
let action = self.curr_tour[curr_tour_id].action.clone();
self.state.move_forward(&action);
self.direct_road.push(action);
self.curr_tour.pop();
curr_tour_id += 1;
}
let mut leaf_id = 0;
for edge in &self.curr_tour[curr_tour_id..] {
match edge.property {
EdgeProperty::Leaf => {
if self.buckets[leaf_id].is_empty() {
leaf_id += 1;
continue;
}
self.next_tour.push(Edge {
property: EdgeProperty::Forward,
action: edge.action.clone(),
});
for (action, evaluator, hash) in &self.buckets[leaf_id] {
self.next_tour.push(Edge {
property: EdgeProperty::Leaf,
action: action.clone(),
});
self.leaves.push((evaluator.clone(), *hash));
}
self.next_tour.push(Edge {
property: EdgeProperty::Backward,
action: edge.action.clone(),
});
self.buckets[leaf_id].clear();
leaf_id += 1;
}
EdgeProperty::Forward => {
self.next_tour.push(edge.clone());
}
EdgeProperty::Backward => {
if self.next_tour.last().unwrap().property == EdgeProperty::Forward {
self.next_tour.pop();
} else {
self.next_tour.push(edge.clone());
}
}
}
}
std::mem::swap(&mut self.curr_tour, &mut self.next_tour);
self.next_tour.clear();
}
// get the path from the root
fn get_path(&self, best_leaf_id: usize, turn: usize) -> Vec<Action> {
// eprintln!("curr_tour.len() = {}", self.curr_tour.capacity());
let mut ret = self.direct_road.clone();
ret.reserve(turn);
let mut leaf_id = 0;
for edge in &self.curr_tour {
match edge.property {
EdgeProperty::Leaf => {
if leaf_id == best_leaf_id {
ret.push(edge.action.clone());
return ret;
}
leaf_id += 1;
}
EdgeProperty::Forward => ret.push(edge.action.clone()),
EdgeProperty::Backward => {
ret.pop();
}
}
}
panic!("invalid argument: best_leaf_id");
}
}
pub fn beam_search(config: &Config, state: State) -> Vec<Action> {
let mut tree = Tree::new(state, config);
let mut selector = Selector::new(config.beam_width, config.hash_que_turn);
for turn in 0..config.max_turn {
tree.dfs(&mut selector);
if let Some(candidate) = &selector.finished_candidate {
// find the feasible solution in turn minimizing problem
let mut ret = tree.get_path(candidate.parent as usize, turn + 1);
ret.push(candidate.action.clone());
return ret;
}
debug_assert!(!selector.candidates.is_empty());
tree.update(&selector.candidates);
selector.clear();
}
unreachable!();
}
#[derive(Debug, Clone)]
pub struct Input {
num_ore_type: usize,
grid: [[u8; N + 2]; N + 2],
holes: [(usize, usize); M_MAX],
}
impl Input {
fn read() -> Self {
input! {
n: usize,
m: usize,
c: [String; n],
}
debug_assert_eq!(n, N);
let c = c.iter().map(|s| s.chars().collect_vec()).collect_vec();
let mut grid = [[WALL; N + 2]; N + 2];
for x in 0..n {
for y in 0..n {
grid[x + 1][y + 1] = char_to_u8(c[x][y]);
}
}
let mut holes = [(usize::MAX, usize::MAX); 3];
for x in 1..=N {
for y in 1..=N {
if grid[x][y] == A {
holes[0] = (x, y);
} else if grid[x][y] == B {
holes[1] = (x, y);
} else if grid[x][y] == C {
holes[2] = (x, y);
}
}
}
Self {
num_ore_type: m,
grid,
holes,
}
}
}
#[derive(Default)]
struct NoHashHasher {
value: u64,
}
impl Hasher for NoHashHasher {
fn write(&mut self, bytes: &[u8]) {
self.value = u64::from_ne_bytes(bytes[..8].try_into().unwrap());
}
fn finish(&self) -> u64 {
self.value
}
}
type NoHashSet = HashSet<u64, BuildHasherDefault<NoHashHasher>>;
pub trait ChangeMinMax {
fn chmin(&mut self, x: Self) -> bool;
fn chmax(&mut self, x: Self) -> bool;
}
impl<T: PartialOrd> ChangeMinMax for T {
fn chmin(&mut self, x: T) -> bool {
*self > x && {
*self = x;
true
}
}
fn chmax(&mut self, x: T) -> bool {
*self < x && {
*self = x;
true
}
}
}
pub fn get_time_sec() -> f64 {
static mut STIME: f64 = -1.0;
let t = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap();
let ms = t.as_secs() as f64 + t.subsec_nanos() as f64 * 1e-9;
unsafe {
if STIME < 0.0 {
STIME = ms;
}
ms - STIME
}
}
提出情報
| 提出日時 |
|
| 問題 |
A - Ore Rolling (A) |
| ユーザ |
eijirou |
| 言語 |
Rust (rustc 1.70.0) |
| 得点 |
914005875 |
| コード長 |
29488 Byte |
| 結果 |
AC |
| 実行時間 |
1546 ms |
| メモリ |
19492 KiB |
ジャッジ結果
| セット名 |
test_ALL |
| 得点 / 配点 |
914005875 / 1500000000 |
| 結果 |
|
| セット名 |
テストケース |
| test_ALL |
test_0000.txt, test_0001.txt, test_0002.txt, test_0003.txt, test_0004.txt, test_0005.txt, test_0006.txt, test_0007.txt, test_0008.txt, test_0009.txt, test_0010.txt, test_0011.txt, test_0012.txt, test_0013.txt, test_0014.txt, test_0015.txt, test_0016.txt, test_0017.txt, test_0018.txt, test_0019.txt, test_0020.txt, test_0021.txt, test_0022.txt, test_0023.txt, test_0024.txt, test_0025.txt, test_0026.txt, test_0027.txt, test_0028.txt, test_0029.txt, test_0030.txt, test_0031.txt, test_0032.txt, test_0033.txt, test_0034.txt, test_0035.txt, test_0036.txt, test_0037.txt, test_0038.txt, test_0039.txt, test_0040.txt, test_0041.txt, test_0042.txt, test_0043.txt, test_0044.txt, test_0045.txt, test_0046.txt, test_0047.txt, test_0048.txt, test_0049.txt, test_0050.txt, test_0051.txt, test_0052.txt, test_0053.txt, test_0054.txt, test_0055.txt, test_0056.txt, test_0057.txt, test_0058.txt, test_0059.txt, test_0060.txt, test_0061.txt, test_0062.txt, test_0063.txt, test_0064.txt, test_0065.txt, test_0066.txt, test_0067.txt, test_0068.txt, test_0069.txt, test_0070.txt, test_0071.txt, test_0072.txt, test_0073.txt, test_0074.txt, test_0075.txt, test_0076.txt, test_0077.txt, test_0078.txt, test_0079.txt, test_0080.txt, test_0081.txt, test_0082.txt, test_0083.txt, test_0084.txt, test_0085.txt, test_0086.txt, test_0087.txt, test_0088.txt, test_0089.txt, test_0090.txt, test_0091.txt, test_0092.txt, test_0093.txt, test_0094.txt, test_0095.txt, test_0096.txt, test_0097.txt, test_0098.txt, test_0099.txt, test_0100.txt, test_0101.txt, test_0102.txt, test_0103.txt, test_0104.txt, test_0105.txt, test_0106.txt, test_0107.txt, test_0108.txt, test_0109.txt, test_0110.txt, test_0111.txt, test_0112.txt, test_0113.txt, test_0114.txt, test_0115.txt, test_0116.txt, test_0117.txt, test_0118.txt, test_0119.txt, test_0120.txt, test_0121.txt, test_0122.txt, test_0123.txt, test_0124.txt, test_0125.txt, test_0126.txt, test_0127.txt, test_0128.txt, test_0129.txt, test_0130.txt, test_0131.txt, test_0132.txt, test_0133.txt, test_0134.txt, test_0135.txt, test_0136.txt, test_0137.txt, test_0138.txt, test_0139.txt, test_0140.txt, test_0141.txt, test_0142.txt, test_0143.txt, test_0144.txt, test_0145.txt, test_0146.txt, test_0147.txt, test_0148.txt, test_0149.txt |
| ケース名 |
結果 |
実行時間 |
メモリ |
| test_0000.txt |
AC |
1343 ms |
18604 KiB |
| test_0001.txt |
AC |
1286 ms |
19492 KiB |
| test_0002.txt |
AC |
1380 ms |
19180 KiB |
| test_0003.txt |
AC |
1335 ms |
18456 KiB |
| test_0004.txt |
AC |
1299 ms |
18660 KiB |
| test_0005.txt |
AC |
1207 ms |
17780 KiB |
| test_0006.txt |
AC |
1245 ms |
18756 KiB |
| test_0007.txt |
AC |
1398 ms |
18372 KiB |
| test_0008.txt |
AC |
1276 ms |
18492 KiB |
| test_0009.txt |
AC |
1152 ms |
18136 KiB |
| test_0010.txt |
AC |
1177 ms |
18440 KiB |
| test_0011.txt |
AC |
1420 ms |
18688 KiB |
| test_0012.txt |
AC |
1445 ms |
18348 KiB |
| test_0013.txt |
AC |
1272 ms |
18688 KiB |
| test_0014.txt |
AC |
1272 ms |
18532 KiB |
| test_0015.txt |
AC |
1247 ms |
18124 KiB |
| test_0016.txt |
AC |
1336 ms |
18432 KiB |
| test_0017.txt |
AC |
1306 ms |
18496 KiB |
| test_0018.txt |
AC |
1426 ms |
18592 KiB |
| test_0019.txt |
AC |
1315 ms |
18896 KiB |
| test_0020.txt |
AC |
1355 ms |
18416 KiB |
| test_0021.txt |
AC |
1319 ms |
18700 KiB |
| test_0022.txt |
AC |
1330 ms |
18272 KiB |
| test_0023.txt |
AC |
1269 ms |
18268 KiB |
| test_0024.txt |
AC |
1292 ms |
17608 KiB |
| test_0025.txt |
AC |
1291 ms |
19292 KiB |
| test_0026.txt |
AC |
1273 ms |
18040 KiB |
| test_0027.txt |
AC |
1435 ms |
18768 KiB |
| test_0028.txt |
AC |
1284 ms |
18536 KiB |
| test_0029.txt |
AC |
1314 ms |
18792 KiB |
| test_0030.txt |
AC |
1334 ms |
18812 KiB |
| test_0031.txt |
AC |
1219 ms |
18776 KiB |
| test_0032.txt |
AC |
1170 ms |
18836 KiB |
| test_0033.txt |
AC |
1379 ms |
18348 KiB |
| test_0034.txt |
AC |
1254 ms |
18240 KiB |
| test_0035.txt |
AC |
1177 ms |
18360 KiB |
| test_0036.txt |
AC |
1153 ms |
18620 KiB |
| test_0037.txt |
AC |
1327 ms |
18188 KiB |
| test_0038.txt |
AC |
1257 ms |
18388 KiB |
| test_0039.txt |
AC |
1385 ms |
18348 KiB |
| test_0040.txt |
AC |
1167 ms |
18840 KiB |
| test_0041.txt |
AC |
1482 ms |
19080 KiB |
| test_0042.txt |
AC |
1546 ms |
18748 KiB |
| test_0043.txt |
AC |
1339 ms |
19072 KiB |
| test_0044.txt |
AC |
1347 ms |
18780 KiB |
| test_0045.txt |
AC |
1464 ms |
19420 KiB |
| test_0046.txt |
AC |
1284 ms |
18056 KiB |
| test_0047.txt |
AC |
1482 ms |
18424 KiB |
| test_0048.txt |
AC |
1394 ms |
18888 KiB |
| test_0049.txt |
AC |
1336 ms |
18108 KiB |
| test_0050.txt |
AC |
1307 ms |
18824 KiB |
| test_0051.txt |
AC |
1472 ms |
18328 KiB |
| test_0052.txt |
AC |
1203 ms |
18592 KiB |
| test_0053.txt |
AC |
1347 ms |
18172 KiB |
| test_0054.txt |
AC |
1487 ms |
19092 KiB |
| test_0055.txt |
AC |
1480 ms |
18664 KiB |
| test_0056.txt |
AC |
1312 ms |
19044 KiB |
| test_0057.txt |
AC |
1351 ms |
18656 KiB |
| test_0058.txt |
AC |
1516 ms |
18228 KiB |
| test_0059.txt |
AC |
1316 ms |
18980 KiB |
| test_0060.txt |
AC |
1298 ms |
19192 KiB |
| test_0061.txt |
AC |
1349 ms |
18776 KiB |
| test_0062.txt |
AC |
1481 ms |
18712 KiB |
| test_0063.txt |
AC |
1527 ms |
19196 KiB |
| test_0064.txt |
AC |
1407 ms |
18456 KiB |
| test_0065.txt |
AC |
1364 ms |
19012 KiB |
| test_0066.txt |
AC |
1321 ms |
18728 KiB |
| test_0067.txt |
AC |
1323 ms |
18676 KiB |
| test_0068.txt |
AC |
1539 ms |
19112 KiB |
| test_0069.txt |
AC |
1204 ms |
18616 KiB |
| test_0070.txt |
AC |
1301 ms |
18152 KiB |
| test_0071.txt |
AC |
1267 ms |
17724 KiB |
| test_0072.txt |
AC |
1472 ms |
18684 KiB |
| test_0073.txt |
AC |
1495 ms |
18612 KiB |
| test_0074.txt |
AC |
1412 ms |
18604 KiB |
| test_0075.txt |
AC |
1434 ms |
18828 KiB |
| test_0076.txt |
AC |
1526 ms |
18760 KiB |
| test_0077.txt |
AC |
1341 ms |
18776 KiB |
| test_0078.txt |
AC |
1479 ms |
18252 KiB |
| test_0079.txt |
AC |
1251 ms |
18456 KiB |
| test_0080.txt |
AC |
1295 ms |
18768 KiB |
| test_0081.txt |
AC |
1339 ms |
18720 KiB |
| test_0082.txt |
AC |
1489 ms |
18496 KiB |
| test_0083.txt |
AC |
1370 ms |
18668 KiB |
| test_0084.txt |
AC |
1493 ms |
18968 KiB |
| test_0085.txt |
AC |
1287 ms |
18484 KiB |
| test_0086.txt |
AC |
1410 ms |
18668 KiB |
| test_0087.txt |
AC |
1379 ms |
18864 KiB |
| test_0088.txt |
AC |
1278 ms |
18532 KiB |
| test_0089.txt |
AC |
1341 ms |
18152 KiB |
| test_0090.txt |
AC |
1275 ms |
18724 KiB |
| test_0091.txt |
AC |
1503 ms |
18612 KiB |
| test_0092.txt |
AC |
1484 ms |
18672 KiB |
| test_0093.txt |
AC |
1326 ms |
18196 KiB |
| test_0094.txt |
AC |
1388 ms |
18168 KiB |
| test_0095.txt |
AC |
1527 ms |
18732 KiB |
| test_0096.txt |
AC |
1354 ms |
18096 KiB |
| test_0097.txt |
AC |
1354 ms |
19236 KiB |
| test_0098.txt |
AC |
1459 ms |
18836 KiB |
| test_0099.txt |
AC |
1448 ms |
18480 KiB |
| test_0100.txt |
AC |
1505 ms |
18264 KiB |
| test_0101.txt |
AC |
1249 ms |
18372 KiB |
| test_0102.txt |
AC |
1393 ms |
18776 KiB |
| test_0103.txt |
AC |
1474 ms |
19092 KiB |
| test_0104.txt |
AC |
1494 ms |
18772 KiB |
| test_0105.txt |
AC |
1386 ms |
17772 KiB |
| test_0106.txt |
AC |
1358 ms |
18656 KiB |
| test_0107.txt |
AC |
1234 ms |
18144 KiB |
| test_0108.txt |
AC |
1454 ms |
18568 KiB |
| test_0109.txt |
AC |
1441 ms |
18136 KiB |
| test_0110.txt |
AC |
1494 ms |
18304 KiB |
| test_0111.txt |
AC |
1479 ms |
18572 KiB |
| test_0112.txt |
AC |
1134 ms |
18720 KiB |
| test_0113.txt |
AC |
1434 ms |
19104 KiB |
| test_0114.txt |
AC |
1301 ms |
18592 KiB |
| test_0115.txt |
AC |
1360 ms |
18456 KiB |
| test_0116.txt |
AC |
1268 ms |
18312 KiB |
| test_0117.txt |
AC |
1423 ms |
18692 KiB |
| test_0118.txt |
AC |
1379 ms |
18532 KiB |
| test_0119.txt |
AC |
1422 ms |
18160 KiB |
| test_0120.txt |
AC |
1276 ms |
18128 KiB |
| test_0121.txt |
AC |
1514 ms |
19160 KiB |
| test_0122.txt |
AC |
1327 ms |
18552 KiB |
| test_0123.txt |
AC |
1213 ms |
18608 KiB |
| test_0124.txt |
AC |
1318 ms |
18092 KiB |
| test_0125.txt |
AC |
1198 ms |
18196 KiB |
| test_0126.txt |
AC |
1314 ms |
18536 KiB |
| test_0127.txt |
AC |
1469 ms |
17936 KiB |
| test_0128.txt |
AC |
1373 ms |
18856 KiB |
| test_0129.txt |
AC |
1308 ms |
18992 KiB |
| test_0130.txt |
AC |
1425 ms |
18344 KiB |
| test_0131.txt |
AC |
1391 ms |
18728 KiB |
| test_0132.txt |
AC |
1449 ms |
18780 KiB |
| test_0133.txt |
AC |
1370 ms |
18764 KiB |
| test_0134.txt |
AC |
1113 ms |
17692 KiB |
| test_0135.txt |
AC |
1250 ms |
18276 KiB |
| test_0136.txt |
AC |
1344 ms |
18652 KiB |
| test_0137.txt |
AC |
1304 ms |
17912 KiB |
| test_0138.txt |
AC |
1347 ms |
18016 KiB |
| test_0139.txt |
AC |
1248 ms |
18524 KiB |
| test_0140.txt |
AC |
1409 ms |
18244 KiB |
| test_0141.txt |
AC |
1260 ms |
18192 KiB |
| test_0142.txt |
AC |
1286 ms |
18600 KiB |
| test_0143.txt |
AC |
1460 ms |
18704 KiB |
| test_0144.txt |
AC |
1485 ms |
19064 KiB |
| test_0145.txt |
AC |
1196 ms |
18368 KiB |
| test_0146.txt |
AC |
1497 ms |
18400 KiB |
| test_0147.txt |
AC |
1395 ms |
18312 KiB |
| test_0148.txt |
AC |
1304 ms |
18652 KiB |
| test_0149.txt |
AC |
1332 ms |
17724 KiB |