結果
問題 | No.5020 Averaging |
ユーザー |
|
提出日時 | 2024-02-25 14:38:14 |
言語 | Rust (1.83.0 + proconio) |
結果 |
AC
|
実行時間 | 903 ms / 1,000 ms |
コード長 | 17,156 bytes |
コンパイル時間 | 1,971 ms |
コンパイル使用メモリ | 195,248 KB |
実行使用メモリ | 6,676 KB |
スコア | 15,164,226 |
最終ジャッジ日時 | 2024-02-25 14:39:04 |
合計ジャッジ時間 | 49,555 ms |
ジャッジサーバーID (参考情報) |
judge13 / judge15 |
純コード判定しない問題か言語 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | AC * 50 |
ソースコード
#![allow(dead_code)]#![allow(non_upper_case_globals)]#![allow(unused_imports)]use crate::{data_structures::{grid::{Coord, Map2d},*,},problem::*,sa::*,utils::*,};use std::{cmp::*, collections::*};const TIME_LIMIT: f64 = 0.90;const N: usize = 45;const W: usize = 5 * 10usize.pow(17);pub fn main() {get_time();let input = read_input();let output = solve(&input);output.print_ans();eprintln!("Time = {}", get_time());}fn solve(input: &Input) -> Output {let mut state = State::new(input);state.score = state.calc_score();let mut solver = SASolver::new(state.clone());solver.run(input, TIME_LIMIT - get_time());let cnt = solver.state.cnt;crate::printdata!(cnt);solver.state.to_output(input)}mod data_structures {use super::*;pub mod grid {#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]pub struct Coord {pub x: usize,pub y: usize,}impl Coord {pub const fn new(x: usize, y: usize) -> Self {Self { x, y }}pub const fn new2(p: usize, width: usize) -> Self {Self {x: p / width,y: p % width,}}pub fn in_map(&self, size: usize) -> bool {self.x < size && self.y < size}pub const fn idx(&self, size: usize) -> usize {self.x * size + self.y}pub fn next(self, dir: usize) -> Self {self + DXY[dir]}pub const fn dist(&self, other: &Self) -> usize {Self::dist_1d(self.x, other.x) + Self::dist_1d(self.y, other.y)}const fn dist_1d(x0: usize, x1: usize) -> usize {x0.abs_diff(x1)}}impl std::ops::Add for Coord {type Output = Self;fn add(self, other: Self) -> Self {Self {x: self.x + other.x,y: self.y + other.y,}}}pub const DXY: [Coord; 4] = [Coord::new(0, !0),Coord::new(!0, 0),Coord::new(0, 1),Coord::new(1, 0),];pub const DC: [char; 4] = ['L', 'U', 'R', 'D'];#[derive(Debug, Clone)]pub struct Map2d<T> {pub height: usize,pub width: usize,map: Vec<T>,}impl<T: Clone> Map2d<T> {pub fn new(map: Vec<T>, width: usize) -> Self {let height = map.len() / width;debug_assert!(width * height == map.len());Self { height, width, map }}pub fn fill(&mut self, value: T) {self.map.fill(value);}}impl<T> std::ops::Index<Coord> for Map2d<T> {type Output = T;#[inline]fn index(&self, coord: Coord) -> &Self::Output {unsafe { self.map.get_unchecked(coord.x * self.width + coord.y) }}}impl<T> std::ops::IndexMut<Coord> for Map2d<T> {#[inline]fn index_mut(&mut self, coord: Coord) -> &mut Self::Output {unsafe { self.map.get_unchecked_mut(coord.x * self.width + coord.y) }}}impl<T> std::ops::Index<&Coord> for Map2d<T> {type Output = T;#[inline]fn index(&self, coord: &Coord) -> &Self::Output {&self.map[coord.x * self.width + coord.y]}}impl<T> std::ops::IndexMut<&Coord> for Map2d<T> {#[inline]fn index_mut(&mut self, coord: &Coord) -> &mut Self::Output {&mut self.map[coord.x * self.width + coord.y]}}impl<T> std::ops::Index<usize> for Map2d<T> {type Output = T;#[inline]fn index(&self, p: usize) -> &Self::Output {&self.map[p]}}impl<T> std::ops::IndexMut<usize> for Map2d<T> {#[inline]fn index_mut(&mut self, p: usize) -> &mut Self::Output {&mut self.map[p]}}}}mod problem {use super::*;type ScoreType = f64;#[derive(Debug, Clone)]pub struct State {pub score: ScoreType,pub penalty: ScoreType,pub cards: Vec<Card>,pub rireki: Vec<Vec<(usize, Card)>>, // [i]: i個目のカードがmergeされたもう一方のカードのindexとmergeされるのカードpub cnt: usize,}impl State {pub fn new(input: &Input) -> Self {Self {score: 0.0,penalty: 0.0,cards: input.cards.clone(),rireki: vec![vec![]; input.n],cnt: 0,}}pub fn calc_score(&self) -> ScoreType {let diff_a = self.cards[0].a.abs_diff(W);let diff_b = self.cards[0].b.abs_diff(W);let diff = max(diff_a, diff_b);(diff as f64 + 1.0).log10()}pub fn apply(&mut self, action: (usize, usize)) {self.rireki[action.0].push((action.1, self.cards[action.0]));self.rireki[action.1].push((action.0, self.cards[action.1]));let next_a = (self.cards[action.0].a + self.cards[action.1].a) / 2;let next_b = (self.cards[action.0].b + self.cards[action.1].b) / 2;self.cards[action.0].a = next_a;self.cards[action.0].b = next_b;self.cards[action.1].a = next_a;self.cards[action.1].b = next_b;self.score = self.calc_score();self.cnt += 1;self.penalty = (self.cnt as f64 - 50.0).max(0.0);}pub fn revert(&mut self, action: (usize, usize)) {assert!(self.rireki[action.0].len() > 0);assert!(self.rireki[action.1].len() > 0);let aa = self.rireki[action.0].len();self.cards[action.0] = self.rireki[action.0].last().unwrap().1;self.cards[action.1] = self.rireki[action.1].last().unwrap().1;self.rireki[action.0].pop();self.rireki[action.1].pop();assert!(self.rireki[action.0].len() == aa - 1);self.score = self.calc_score();self.cnt -= 1;self.penalty = (self.cnt as f64 - 50.0).max(0.0);}pub fn to_output(&mut self, input: &Input) -> Output {let mut actions = vec![];while self.rireki.iter().any(|x| !x.is_empty()) {let u = rnd::get(input.n);if self.rireki[u].is_empty() {continue;}let v = self.rireki[u].last().unwrap().0;if self.rireki[v].last().unwrap().0 != u {continue;}actions.push((u, v));self.rireki[u].pop();self.rireki[v].pop();}Output {score: self.score,actions,}}}#[derive(Debug, Clone, Copy, PartialEq, Eq)]pub struct Card {a: usize,b: usize,}impl Card {fn new(a: usize, b: usize) -> Self {Self { a, b }}}pub struct Input {pub n: usize,pub cards: Vec<Card>,}pub fn read_input() -> Input {let n = input_1::<usize>();let mut cards = vec![];for _ in 0..n {let v = input_vec1::<usize>();cards.push(Card::new(v[0], v[1]));}Input { n, cards }}pub struct Output {pub score: ScoreType,pub actions: Vec<(usize, usize)>,}impl Output {pub fn print_ans(&self) {let score = 2e6 - 1e5 * self.score;crate::printdata!(score);assert!(self.actions.len() <= 50);println!("{}", self.actions.len());for &(a, b) in self.actions.iter() {assert!(a != b);println!("{} {}", a + 1, b + 1);}}}fn input_1<T: std::str::FromStr>() -> Twhere<T as std::str::FromStr>::Err: core::fmt::Debug,{let mut a = String::new();std::io::stdin().read_line(&mut a).unwrap();a.trim().parse().unwrap()}fn input_vec1<T: std::str::FromStr>() -> Vec<T> {let mut a = String::new();std::io::stdin().read_line(&mut a).unwrap();a.trim().split_whitespace().map(|e| e.parse().ok().unwrap()).collect()}}mod sa {use super::*;type ScoreType = f64;pub struct SASolver {start_time: f64,duration: f64,temp: f64,log_table: [f64; 65536],pub state: State,best_state: State,time: f64,mae_kousin_best: f64,regal_iter: usize,}impl SASolver {const GOAL: OptimizationGoal = OptimizationGoal::Min;const START_TEMP: f64 = 10000.0;const END_TEMP: f64 = 0.01;const DIFF_TEMP: f64 = Self::END_TEMP / Self::START_TEMP;pub fn new(state: State) -> Self {let mut log_table = [0.0; 65536];for i in 0..65536 {log_table[i] = ((i as f64 + 0.5) / 65536.0).ln();}rnd::shuffle(&mut log_table);Self {start_time: 0.0,duration: 0.0,temp: 0.0,log_table,state: state.clone(),best_state: state.clone(),time: 0.0,mae_kousin_best: 0.0,regal_iter: 0,}}fn update(&mut self) -> bool {self.time = get_time();if self.time - self.start_time > self.duration {return false;}// 非線形//self.temp =// Self::START_TEMP * Self::DIFF_TEMP.powf((self.time - self.start_time) / self.duration);// 線形//self.temp = Self::START_TEMP// + (Self::END_TEMP - Self::START_TEMP) * (get_time() - self.start_time) / self.duration;//self.temp = Self::START_TEMP* Self::DIFF_TEMP.powf(((self.time - self.start_time) / self.duration).powf(1.5));true}fn select_neighborhood(&mut self, input: &Input, _iter: usize) -> Box<dyn Neighbor> {const CNT_NEIGHBORHOOD: usize = 2;static neighborhood_ratio: [usize; CNT_NEIGHBORHOOD] = [50, 100];let op = rnd::get(100);if op < neighborhood_ratio[0] {Box::new(neighborhood::Apply::new(input, &self.state))} else {Box::new(neighborhood::Revert::new(input, &self.state))}}fn update_best_state(&mut self) -> bool {if self.state.cnt > 50 {return false;}if Self::GOAL == OptimizationGoal::Max {if self.state.score > self.best_state.score {self.best_state = self.state.clone();self.mae_kousin_best = self.time;return true;}} else {if self.state.score < self.best_state.score {self.best_state = self.state.clone();self.mae_kousin_best = self.time;return true;}}false}fn is_accepted(&mut self,_input: &Input,pre_score: (ScoreType, ScoreType),next_score: (ScoreType, ScoreType),iter_sa: usize,) -> bool {self.regal_iter += 1;let ss = 10000.0;let pre_score = pre_score.0 as f64+ ss * pre_score.1 as f64 * (self.time - self.start_time) / self.duration as f64;let next_score = next_score.0 as f64+ ss * next_score.1 as f64 * (self.time - self.start_time) / self.duration as f64;if Self::GOAL == OptimizationGoal::Max {next_score as f64 - pre_score as f64>= self.temp as f64 * self.log_table[iter_sa & 65535] as f64} else {-(next_score as f64 - pre_score as f64)>= self.temp as f64 * self.log_table[iter_sa & 65535] as f64}}pub fn run(&mut self, input: &Input, duration: f64) {self.start_time = get_time();self.duration = duration;let mut iter_sa = 0;let mut cnt_ac = 0;let mut cnt_upd_best = 0;while iter_sa & 127 != 0 || self.update() {iter_sa += 1;let pre_score = (self.state.score, self.state.penalty);let neighbor: Box<dyn Neighbor> = self.select_neighborhood(input, iter_sa);if neighbor.preprocess(input, &mut self.state)&& self.is_accepted(input,pre_score,(self.state.score, self.state.penalty),iter_sa,){neighbor.postprocess(input, &mut self.state);if self.update_best_state() {cnt_upd_best += 1;}cnt_ac += 1;} else {neighbor.rollback(input, &mut self.state, pre_score);}}crate::printdata!(iter_sa);eprintln!("regal_iter: {}", self.regal_iter);eprintln!("cnt_ac: {}", cnt_ac);eprintln!("cnt_upd_best: {}", cnt_upd_best);eprintln!("mae_kousin_best: {}", self.mae_kousin_best);self.state = self.best_state.clone();}}#[derive(PartialEq)]enum OptimizationGoal {Max,Min,}trait Neighbor {fn preprocess(&self, input: &Input, state: &mut State) -> bool;fn postprocess(&self, input: &Input, state: &mut State);fn rollback(&self, input: &Input, state: &mut State, pre_score: (ScoreType, ScoreType));}mod neighborhood {use super::*;pub struct Apply {action: (usize, usize),}impl Apply {pub fn new(input: &Input, _state: &State) -> Self {let u = rnd::get(input.n);let v = rnd::range_skip(0, input.n, u);assert!(u != v);Self { action: (u, v) }}}impl Neighbor for Apply {fn preprocess(&self, _input: &Input, state: &mut State) -> bool {state.apply(self.action);true}fn postprocess(&self, _input: &Input, _state: &mut State) {}fn rollback(&self, _input: &Input, state: &mut State, _pre_score: (ScoreType, ScoreType)) {state.revert(self.action);}}pub struct Revert {action: (usize, usize),}impl Revert {pub fn new(input: &Input, state: &State) -> Self {if state.penalty < 1e-9 {return Self { action: (!0, !0) };}loop {let u = rnd::get(input.n);if state.rireki[u].len() == 0 {continue;}let v = state.rireki[u].last().unwrap().0;if u != state.rireki[v].last().unwrap().0 {continue;}return Self { action: (u, v) };}}}impl Neighbor for Revert {fn preprocess(&self, _input: &Input, state: &mut State) -> bool {if self.action == (!0, !0) {return false;}state.revert(self.action);true}fn postprocess(&self, _input: &Input, _state: &mut State) {}fn rollback(&self, _input: &Input, state: &mut State, _pre_score: (ScoreType, ScoreType)) {if self.action == (!0, !0) {return;}state.apply(self.action);}}}}mod utils {use super::*;#[macro_export]macro_rules! printdata {( $($x:expr),* ) => {{$(eprintln!("[DATA] {} = {:?}", stringify!($x), $x);)*}}}pub mod rnd {static mut A: u64 = 1;pub fn next() -> u32 {unsafe {let mut x = A;A *= 0xcafef00dd15ea5e5;x ^= x >> 22;(x >> 22 + (x >> 61)) as u32}}pub fn next64() -> u64 {(next() as u64) << 32 | next() as u64}pub fn nextf() -> f64 {unsafe { std::mem::transmute::<u64, f64>(0x3ff0000000000000 | (next() as u64) << 20) - 1. }}pub fn get(n: usize) -> usize {assert!(n <= u32::MAX as usize);next() as usize * n >> 32}pub fn range(a: usize, b: usize) -> usize {assert!(a < b);get(b - a) + a}pub fn range_skip(a: usize, b: usize, skip: usize) -> usize {assert!(a <= skip && skip < b);let n = range(a, b - 1);n + (skip <= n) as usize}pub fn rangei(a: i64, b: i64) -> i64 {assert!(a < b);get((b - a) as usize) as i64 + a}pub fn shuffle<T>(list: &mut [T]) {for i in (0..list.len()).rev() {list.swap(i, get(i + 1));}}pub fn shuffle_iter<T: Copy>(list: &mut [T]) -> impl Iterator<Item = T> + '_ {(0..list.len()).rev().map(|i| {list.swap(i, get(i + 1));list[i]})}}pub trait RandomChoice {type Output;fn choice(&self) -> Self::Output;}impl<T: Copy> RandomChoice for [T] {type Output = T;fn choice(&self) -> T {self[rnd::get(self.len())]}}pub fn get_time() -> f64 {static mut START: f64 = -1.0;let end = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs_f64();unsafe {if START < 0.0 {START = end;}end - START}}}