提出 #32967760


ソースコード 拡げる

use std::{fmt::Display, time::Instant};

use itertools::izip;
#[allow(unused_imports)]
use proconio::*;
#[allow(unused_imports)]
use rand::prelude::*;

#[allow(unused_macros)]
macro_rules! chmin {
    ($base:expr, $($cmps:expr),+ $(,)*) => {{
        let cmp_min = min!($($cmps),+);
        if $base > cmp_min {
            $base = cmp_min;
            true
        } else {
            false
        }
    }};
}

#[allow(unused_macros)]
macro_rules! chmax {
    ($base:expr, $($cmps:expr),+ $(,)*) => {{
        let cmp_max = max!($($cmps),+);
        if $base < cmp_max {
            $base = cmp_max;
            true
        } else {
            false
        }
    }};
}

#[allow(unused_macros)]
macro_rules! min {
    ($a:expr $(,)*) => {{
        $a
    }};
    ($a:expr, $b:expr $(,)*) => {{
        std::cmp::min($a, $b)
    }};
    ($a:expr, $($rest:expr),+ $(,)*) => {{
        std::cmp::min($a, min!($($rest),+))
    }};
}

#[allow(unused_macros)]
macro_rules! max {
    ($a:expr $(,)*) => {{
        $a
    }};
    ($a:expr, $b:expr $(,)*) => {{
        std::cmp::max($a, $b)
    }};
    ($a:expr, $($rest:expr),+ $(,)*) => {{
        std::cmp::max($a, max!($($rest),+))
    }};
}

#[allow(unused_macros)]
macro_rules! mat {
    ($e:expr; $d:expr) => { vec![$e; $d] };
    ($e:expr; $d:expr $(; $ds:expr)+) => { vec![mat![$e $(; $ds)*]; $d] };
}

const RADIUS: i64 = 10000;
const COUNT_MIN: usize = 1;
const COUNT_MAX: usize = 11;

#[derive(Debug, Clone)]
struct Input {
    n: usize,
    k: usize,
    counts: Vec<i32>,
    count_sum: i32,
    points: Vec<Point>,
    since: Instant,
}

#[derive(Debug, Clone, Copy)]
struct Point {
    x: i64,
    y: i64,
}

impl Point {
    fn new(x: i64, y: i64) -> Self {
        Self { x, y }
    }
}

#[derive(Debug, Clone)]
struct State {
    /// 縦方向カットのx座標
    v_cut: Vec<i64>,
    /// 横方向カットのy座標
    h_cut: Vec<i64>,
    cut_count_v: usize,
    box_count_v: usize,
    cut_count_h: usize,
    box_count_h: usize,
    boxes: Vec<Vec<Vec<Point>>>,
    counts: Vec<i32>,
}

impl State {
    fn init(input: &Input) -> Self {
        let mut v_cut = vec![];
        let mut h_cut = vec![];

        let mut cut_count_v = 1;
        let cut_count_h = 7;

        while cut_count_v * cut_count_h < input.count_sum as usize {
            cut_count_v += 1;
        }

        // 適当に余裕を持たせる
        cut_count_v += 5;
        chmin!(cut_count_v, input.k - cut_count_h);
        let box_count_v = cut_count_v + 1;
        let box_count_h = cut_count_h + 1;
        eprintln!("{}", box_count_v);

        let min = -RADIUS - 1;
        let max = RADIUS + 1;

        for i in 0..=box_count_v {
            let x = (max - min) * i as i64 / box_count_v as i64 + min;
            v_cut.push(x);
        }

        for i in 0..=box_count_h {
            let x = (max - min) * i as i64 / box_count_h as i64 + min;
            h_cut.push(x);
        }

        let (boxes, counts) =
            State::count_all_inner(&v_cut, &h_cut, box_count_v, box_count_h, input);
        let state = State {
            v_cut,
            h_cut,
            cut_count_v,
            box_count_v,
            cut_count_h,
            box_count_h,
            boxes,
            counts,
        };

        state
    }

    fn count_all_inner(
        v_cut: &[i64],
        h_cut: &[i64],
        box_count_v: usize,
        box_count_h: usize,
        input: &Input,
    ) -> (Vec<Vec<Vec<Point>>>, Vec<i32>) {
        let mut boxes = mat![vec![]; box_count_v * 2 + 1; box_count_h * 2 + 1];

        for point in input.points.iter() {
            let i = match v_cut[1..(v_cut.len() - 1)].binary_search(&point.x) {
                Ok(i) => 2 * i + 1,
                Err(i) => 2 * i,
            };

            let j = match h_cut[1..(h_cut.len() - 1)].binary_search(&point.y) {
                Ok(j) => 2 * j + 1,
                Err(j) => 2 * j,
            };

            boxes[i][j].push(*point);
        }

        let mut counts = vec![0; input.points.len() + 1];

        for i in 0..box_count_v {
            let i = 2 * i;
            for j in 0..box_count_h {
                let j = 2 * j;
                counts[boxes[i][j].len()] += 1;
            }
        }

        (boxes, counts)
    }

    fn calc_score(&self, input: &Input) -> i64 {
        let mut count = 0;

        for (&c0, &c1) in izip!(
            self.counts[COUNT_MIN..COUNT_MAX].iter(),
            input.counts.iter()
        ) {
            count += c0.min(c1);
        }

        (1e6 * count as f64 / input.count_sum as f64).round() as i64
    }

    fn calc_annealing_score(&self, input: &Input, time: f64) -> i64 {
        let mut score = 0;
        let mut c0 = [0; 12];
        let mut c1 = [0; 15];
        for (i, c) in input.counts.iter().enumerate() {
            c0[i + 1] = *c;
        }

        for (i, c) in self.counts[..c1.len()].iter().enumerate() {
            c1[i] = *c;
        }
        c1[14] = std::i32::MAX;

        let mut j = 1;

        for i in 0..c0.len() {
            while c0[i] > 0 {
                while c1[j] == 0 {
                    j += 1;
                }

                let c = c0[i].min(c1[j]);
                c0[i] -= c;
                c1[j] -= c;
                let diff = i as i64 - j as i64;
                score -= diff * diff * c as i64;
            }
        }

        let score = score as f64 * 1000.0 * (1.0 - time);

        score as i64 + self.calc_score(input)
    }

    fn move_lower_v(&mut self, index: usize, diff: i64) {
        self.sub_count_partial_v(index - 1);
        self.sub_count_partial_v(index);
        let line = index * 2 - 1;
        let new_x = self.v_cut[index] + diff;
        let (p, n) = self.boxes.split_at_mut(line);
        let prev = p.last_mut().unwrap();
        let (p, n) = n.split_at_mut(1);
        let line = p.first_mut().unwrap();
        let next = n.first_mut().unwrap();

        // まず線上
        for j in 0..line.len() {
            for p in line[j].iter() {
                next[j].push(*p);
            }

            line[j].clear();
        }

        // 次
        for j in 0..prev.len() {
            for k in (0..prev[j].len()).rev() {
                if prev[j][k].x > new_x {
                    next[j].push(prev[j].swap_remove(k));
                } else if prev[j][k].x == new_x {
                    line[j].push(prev[j].swap_remove(k));
                }
            }
        }

        self.add_count_partial_v(index - 1);
        self.add_count_partial_v(index);
    }

    fn move_upper_v(&mut self, index: usize, diff: i64) {
        self.sub_count_partial_v(index - 1);
        self.sub_count_partial_v(index);
        let line = index * 2 - 1;
        let new_x = self.v_cut[index] + diff;
        let (p, n) = self.boxes.split_at_mut(line);
        let prev = p.last_mut().unwrap();
        let (p, n) = n.split_at_mut(1);
        let line = p.first_mut().unwrap();
        let next = n.first_mut().unwrap();

        // まず線上
        for j in 0..line.len() {
            for p in line[j].iter() {
                prev[j].push(*p);
            }

            line[j].clear();
        }

        // 次
        for j in 0..next.len() {
            for k in (0..next[j].len()).rev() {
                if next[j][k].x < new_x {
                    prev[j].push(next[j].swap_remove(k));
                } else if next[j][k].x == new_x {
                    line[j].push(next[j].swap_remove(k));
                }
            }
        }

        self.add_count_partial_v(index - 1);
        self.add_count_partial_v(index);
    }

    fn move_lower_h(&mut self, index: usize, diff: i64) {
        self.sub_count_partial_h(index - 1);
        self.sub_count_partial_h(index);
        let line = index * 2 - 1;
        let new_y = self.h_cut[index] + diff;

        // まず線上
        for i in 0..self.boxes.len() {
            let b = &mut self.boxes[i];
            let (p, n) = b.split_at_mut(line + 1);
            let line = p.last_mut().unwrap();
            let next = n.first_mut().unwrap();

            for p in line.iter() {
                next.push(*p);
            }

            line.clear();
        }

        // 次
        for i in 0..self.boxes.len() {
            let b = &mut self.boxes[i];
            let (p, n) = b.split_at_mut(line);
            let prev = p.last_mut().unwrap();
            let (p, n) = n.split_at_mut(1);
            let line = p.first_mut().unwrap();
            let next = n.first_mut().unwrap();

            for k in (0..prev.len()).rev() {
                if prev[k].y > new_y {
                    next.push(prev.swap_remove(k));
                } else if prev[k].y == new_y {
                    line.push(prev.swap_remove(k));
                }
            }
        }

        self.add_count_partial_h(index - 1);
        self.add_count_partial_h(index);
    }

    fn move_upper_h(&mut self, index: usize, diff: i64) {
        self.sub_count_partial_h(index - 1);
        self.sub_count_partial_h(index);
        let line = index * 2 - 1;
        let new_y = self.h_cut[index] + diff;

        // まず線上
        for i in 0..self.boxes.len() {
            let b = &mut self.boxes[i];
            let (p, n) = b.split_at_mut(line);
            let prev = p.last_mut().unwrap();
            let line = n.first_mut().unwrap();

            for p in line.iter() {
                prev.push(*p);
            }

            line.clear();
        }

        // 次
        for i in 0..self.boxes.len() {
            let b = &mut self.boxes[i];
            let (p, n) = b.split_at_mut(line);
            let prev = p.last_mut().unwrap();
            let (p, n) = n.split_at_mut(1);
            let line = p.first_mut().unwrap();
            let next = n.first_mut().unwrap();

            for k in (0..next.len()).rev() {
                if next[k].y < new_y {
                    prev.push(next.swap_remove(k));
                } else if next[k].y == new_y {
                    line.push(next.swap_remove(k));
                }
            }
        }

        self.add_count_partial_h(index - 1);
        self.add_count_partial_h(index);
    }

    fn sub_count_partial_v(&mut self, i: usize) {
        let i = 2 * i;

        for j in 0..self.box_count_h {
            let j = 2 * j;
            self.counts[self.boxes[i][j].len()] -= 1;
        }
    }

    fn add_count_partial_v(&mut self, i: usize) {
        let i = 2 * i;

        for j in 0..self.box_count_h {
            let j = 2 * j;
            self.counts[self.boxes[i][j].len()] += 1;
        }
    }

    fn sub_count_partial_h(&mut self, j: usize) {
        let j = 2 * j;

        for i in 0..self.box_count_v {
            let i = 2 * i;
            self.counts[self.boxes[i][j].len()] -= 1;
        }
    }

    fn add_count_partial_h(&mut self, j: usize) {
        let j = 2 * j;

        for i in 0..self.box_count_v {
            let i = 2 * i;
            self.counts[self.boxes[i][j].len()] += 1;
        }
    }
}

impl Display for State {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        writeln!(f, "{}", self.cut_count_v + self.cut_count_h)?;
        for x in self.v_cut[1..(self.v_cut.len() - 1)].iter() {
            writeln!(f, "{} {} {} {}", x, RADIUS + 1, x, -RADIUS - 1)?;
        }

        for y in self.h_cut[1..(self.h_cut.len() - 1)].iter() {
            writeln!(f, "{} {} {} {}", RADIUS + 1, y, -RADIUS - 1, y)?;
        }

        Ok(())
    }
}

fn main() {
    let input = read_input();
    let state = solve(&input);
    println!("{}", &state);
    eprintln!("final score: {}", state.calc_score(&input));

    let elapsed = (Instant::now() - input.since).as_millis();
    eprintln!("elapsed: {}ms", elapsed);
}

fn read_input() -> Input {
    input! {
        n: usize,
        k: usize,
        counts: [i32; 10]
    }

    let mut points = vec![];

    for _ in 0..n {
        input! {
            x: i64,
            y: i64,
        }

        let point = Point::new(x, y);
        points.push(point);
    }

    let since = Instant::now();

    let count_sum = counts.iter().sum();

    let input = Input {
        n,
        k,
        counts,
        count_sum,
        points,
        since,
    };

    return input;
}

fn solve(input: &Input) -> State {
    let state = State::init(&input);
    let state = annealing(input, state, 2.97);
    state
}

fn annealing(input: &Input, initial_solution: State, duration: f64) -> State {
    let mut solution = initial_solution;
    let mut best_solution = solution.clone();
    let mut current_score = solution.calc_annealing_score(input, 0.0);
    let init_score = current_score;
    let mut best_score = current_score;

    let mut all_iter = 0;
    let mut valid_iter = 0;
    let mut accepted_count = 0;
    let mut update_count = 0;
    let mut rng = rand_pcg::Pcg64Mcg::new(42);

    let duration_inv = 1.0 / duration;
    let since = std::time::Instant::now();
    let mut time = 0.0;

    let temp0 = 1e4;
    let temp1 = 1e2;
    let mut inv_temp = 1.0 / temp0;
    let v_prob = solution.cut_count_v as f64 / (solution.cut_count_v + solution.cut_count_h) as f64;

    while time < 1.0 {
        all_iter += 1;
        if (all_iter & ((1 << 4) - 1)) == 0 {
            time = (std::time::Instant::now() - since).as_secs_f64() * duration_inv;
            let temp = f64::powf(temp0, 1.0 - time) * f64::powf(temp1, time);
            inv_temp = 1.0 / temp;
        }

        // 変形
        const MAX_DIFF: i64 = 100;
        let is_v = rng.gen_bool(v_prob);
        let coordinates = if is_v {
            &solution.v_cut
        } else {
            &solution.h_cut
        };

        let cut_count = if is_v {
            solution.cut_count_v
        } else {
            solution.cut_count_h
        };

        let index = rng.gen_range(1, cut_count + 1);

        let prev = coordinates[index - 1];
        let target = coordinates[index];
        let next = coordinates[index + 1];

        let min = (target - MAX_DIFF).max(prev + 1);
        let max = (target + MAX_DIFF).min(next - 1);
        let mut new_p = target;
        let mut trial = 0;

        while new_p == target && trial < 10 {
            new_p = rng.gen_range(min, max + 1);
            trial += 1;
        }

        let diff = new_p - target;

        if diff > 0 {
            if is_v {
                solution.move_upper_v(index, diff);
            } else {
                solution.move_upper_h(index, diff)
            }
        } else if diff < 0 {
            if is_v {
                solution.move_lower_v(index, diff);
            } else {
                solution.move_lower_h(index, diff);
            }
        } else {
            continue;
        }

        if is_v {
            solution.v_cut[index] += diff;
        } else {
            solution.h_cut[index] += diff;
        }

        // スコア計算
        let new_score = solution.calc_annealing_score(input, time);
        let score_diff = new_score - current_score;

        if score_diff >= 0 || rng.gen_bool(f64::exp(score_diff as f64 * inv_temp)) {
            // 解の更新
            current_score = new_score;
            accepted_count += 1;

            if chmax!(best_score, current_score) {
                best_solution = solution.clone();
                update_count += 1;
            }
        } else {
            let diff = -diff;
            if diff > 0 {
                if is_v {
                    solution.move_upper_v(index, diff);
                } else {
                    solution.move_upper_h(index, diff)
                }
            } else if diff < 0 {
                if is_v {
                    solution.move_lower_v(index, diff);
                } else {
                    solution.move_lower_h(index, diff);
                }
            } else {
                continue;
            }

            if is_v {
                solution.v_cut[index] += diff;
            } else {
                solution.h_cut[index] += diff;
            }
        }

        if valid_iter % 50000 == 0 {
            println!("{}", &solution);
        }

        valid_iter += 1;
    }

    eprintln!("===== annealing =====");
    eprintln!("score      : {}", best_score);
    eprintln!("init score : {}", init_score);
    eprintln!("all iter   : {}", all_iter);
    eprintln!("valid iter : {}", valid_iter);
    eprintln!("accepted   : {}", accepted_count);
    eprintln!("updated    : {}", update_count);
    eprintln!("");

    best_solution
}

提出情報

提出日時
問題 A - AtCoder 10th Anniversary
ユーザ terry_u16
言語 Rust (1.42.0)
得点 99206132
コード長 17220 Byte
結果 AC
実行時間 2978 ms
メモリ 4196 KiB

ジャッジ結果

セット名 test_ALL
得点 / 配点 99206132 / 100000000
結果
AC × 100
セット名 テストケース
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_0000.txt AC 2978 ms 4012 KiB
test_0001.txt AC 2975 ms 3860 KiB
test_0002.txt AC 2974 ms 3796 KiB
test_0003.txt AC 2974 ms 3888 KiB
test_0004.txt AC 2973 ms 3824 KiB
test_0005.txt AC 2974 ms 3768 KiB
test_0006.txt AC 2973 ms 3732 KiB
test_0007.txt AC 2974 ms 3828 KiB
test_0008.txt AC 2972 ms 3732 KiB
test_0009.txt AC 2973 ms 3788 KiB
test_0010.txt AC 2974 ms 3728 KiB
test_0011.txt AC 2974 ms 3848 KiB
test_0012.txt AC 2974 ms 3824 KiB
test_0013.txt AC 2974 ms 3632 KiB
test_0014.txt AC 2973 ms 3696 KiB
test_0015.txt AC 2973 ms 3928 KiB
test_0016.txt AC 2972 ms 3764 KiB
test_0017.txt AC 2973 ms 3720 KiB
test_0018.txt AC 2973 ms 3908 KiB
test_0019.txt AC 2974 ms 3780 KiB
test_0020.txt AC 2973 ms 3596 KiB
test_0021.txt AC 2973 ms 3648 KiB
test_0022.txt AC 2973 ms 3636 KiB
test_0023.txt AC 2973 ms 3712 KiB
test_0024.txt AC 2973 ms 3596 KiB
test_0025.txt AC 2976 ms 3804 KiB
test_0026.txt AC 2973 ms 3848 KiB
test_0027.txt AC 2973 ms 3728 KiB
test_0028.txt AC 2974 ms 4024 KiB
test_0029.txt AC 2973 ms 3684 KiB
test_0030.txt AC 2973 ms 4192 KiB
test_0031.txt AC 2973 ms 3772 KiB
test_0032.txt AC 2976 ms 4008 KiB
test_0033.txt AC 2972 ms 3704 KiB
test_0034.txt AC 2973 ms 3604 KiB
test_0035.txt AC 2973 ms 3716 KiB
test_0036.txt AC 2973 ms 3732 KiB
test_0037.txt AC 2973 ms 3540 KiB
test_0038.txt AC 2974 ms 3912 KiB
test_0039.txt AC 2975 ms 3912 KiB
test_0040.txt AC 2973 ms 3768 KiB
test_0041.txt AC 2975 ms 3708 KiB
test_0042.txt AC 2973 ms 3680 KiB
test_0043.txt AC 2974 ms 4048 KiB
test_0044.txt AC 2974 ms 3884 KiB
test_0045.txt AC 2973 ms 3892 KiB
test_0046.txt AC 2972 ms 3596 KiB
test_0047.txt AC 2973 ms 3944 KiB
test_0048.txt AC 2973 ms 3888 KiB
test_0049.txt AC 2974 ms 4036 KiB
test_0050.txt AC 2973 ms 3624 KiB
test_0051.txt AC 2973 ms 3752 KiB
test_0052.txt AC 2973 ms 3824 KiB
test_0053.txt AC 2974 ms 3980 KiB
test_0054.txt AC 2975 ms 3744 KiB
test_0055.txt AC 2974 ms 3800 KiB
test_0056.txt AC 2973 ms 3492 KiB
test_0057.txt AC 2973 ms 3752 KiB
test_0058.txt AC 2973 ms 3656 KiB
test_0059.txt AC 2975 ms 3640 KiB
test_0060.txt AC 2974 ms 3836 KiB
test_0061.txt AC 2976 ms 3900 KiB
test_0062.txt AC 2973 ms 4024 KiB
test_0063.txt AC 2974 ms 3652 KiB
test_0064.txt AC 2973 ms 3532 KiB
test_0065.txt AC 2974 ms 3664 KiB
test_0066.txt AC 2974 ms 3736 KiB
test_0067.txt AC 2975 ms 4088 KiB
test_0068.txt AC 2973 ms 3808 KiB
test_0069.txt AC 2973 ms 3944 KiB
test_0070.txt AC 2972 ms 3420 KiB
test_0071.txt AC 2973 ms 3856 KiB
test_0072.txt AC 2973 ms 3788 KiB
test_0073.txt AC 2973 ms 3664 KiB
test_0074.txt AC 2973 ms 3952 KiB
test_0075.txt AC 2973 ms 3680 KiB
test_0076.txt AC 2973 ms 3720 KiB
test_0077.txt AC 2974 ms 3768 KiB
test_0078.txt AC 2973 ms 3836 KiB
test_0079.txt AC 2972 ms 3524 KiB
test_0080.txt AC 2973 ms 3944 KiB
test_0081.txt AC 2973 ms 4124 KiB
test_0082.txt AC 2974 ms 4060 KiB
test_0083.txt AC 2975 ms 4012 KiB
test_0084.txt AC 2975 ms 3776 KiB
test_0085.txt AC 2973 ms 3588 KiB
test_0086.txt AC 2973 ms 3872 KiB
test_0087.txt AC 2976 ms 4196 KiB
test_0088.txt AC 2972 ms 4040 KiB
test_0089.txt AC 2975 ms 4124 KiB
test_0090.txt AC 2973 ms 3836 KiB
test_0091.txt AC 2973 ms 3820 KiB
test_0092.txt AC 2973 ms 3832 KiB
test_0093.txt AC 2973 ms 3664 KiB
test_0094.txt AC 2975 ms 3952 KiB
test_0095.txt AC 2973 ms 3940 KiB
test_0096.txt AC 2973 ms 3928 KiB
test_0097.txt AC 2974 ms 3824 KiB
test_0098.txt AC 2975 ms 3952 KiB
test_0099.txt AC 2973 ms 3908 KiB