結果

問題 No.5020 Averaging
コンテスト
ユーザー Tekyla
提出日時 2026-05-31 17:28:06
言語 Rust
(1.94.0 + proconio + num + itertools)
コンパイル:
/usr/bin/rustc_custom
実行:
./target/release/main
結果
AC  
実行時間 2 ms / 1,000 ms
コード長 11,022 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 4,720 ms
コンパイル使用メモリ 208,284 KB
実行使用メモリ 6,400 KB
スコア 24,362,650
最終ジャッジ日時 2026-05-31 17:28:16
合計ジャッジ時間 7,189 ms
ジャッジサーバーID
(参考情報)
judge3_1 / judge2_1
純コード判定しない問題か言語
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 50
権限があれば一括ダウンロードができます
コンパイルメッセージ
warning: value assigned to `dist` is never read
   --> src/main.rs:214:36
    |
214 |                     let mut dist = 0;
    |                                    ^
    |
    = help: maybe it is overwritten before being read?
    = note: `#[warn(unused_assignments)]` (part of `#[warn(unused)]`) on by default

warning: variable does not need to be mutable
   --> src/main.rs:252:13
    |
252 |         let mut i = 0;
    |             ----^
    |             |
    |             help: remove this `mut`
    |
    = note: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default

warning: value assigned to `dist` is never read
   --> src/main.rs:307:36
    |
307 |                     let mut dist = 0;
    |                                    ^
    |
    = help: maybe it is overwritten before being read?

warning: constant `OPERATION_LIMIT` is never used
 --> src/main.rs:6:7
  |
6 | const OPERATION_LIMIT: usize = 50;
  |       ^^^^^^^^^^^^^^^
  |
  = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default

warning: function `solver1` is never used
  --> src/main.rs:33:4
   |
33 | fn solver1(n: usize, mut ab: Vec<(i64, i64)>) -> Vec<(usize, usize)> {
   |    ^^^^^^^

warning: function `solver2` is never used
   --> src/main.rs:103:4
    |
103 | fn solver2(n: usize, mut ab: Vec<(i64, i64)>) -> Vec<(usize, usize)> {
    |    ^^^^^^^

warning: function `solver3` is never used
   --> src/main.rs:141:4
    |
141 | fn solver3(n: usize, mut ab: Vec<(i64, i64)>) -> Vec<(usize, usize)> {
    |    ^^^^^^^

ソースコード

diff #
raw source code

use proconio::input;
use std::collections::HashSet;

//const LOCAL_EXECUTE:bool = true;
const TARGET: i64 = 500_000_000_000_000_000;
const OPERATION_LIMIT: usize = 50;

fn operatioin(u: usize, v: usize, ab: &mut [(i64, i64)]) {
    let (a1, b1) = ab[u];
    let (a2, b2) = ab[v];
    let am = (a1 + a2) / 2;
    let bm = (b1 + b2) / 2;
    ab[u] = (am, bm);
    ab[v] = (am, bm);
}

fn calc_score(mut ab: Vec<(i64, i64)>, op: &[(usize, usize)]) -> i64 {
    for &(u, v) in op {
        operatioin(u, v, &mut ab);
    }
    let (a, b) = ab[0];
    let v1 = a.abs_diff(TARGET);
    let v2 = b.abs_diff(TARGET);
    let m = v1.max(v2);
    let x = op.len() as i64;
    if m == 0 {
        return 2000050 - x;
    }
    let score = 2000000.0 - 100000.0 * f64::log10(m as f64 + 1.0);
    score as i64
}

fn solver1(n: usize, mut ab: Vec<(i64, i64)>) -> Vec<(usize, usize)> {
    // いったん全部の平均に近づくようにやってみる
    // a_max - a_min と b_max - b_min の一番大きな組み合わせのカードで平均を取る
    let mut ans = vec![];
    for _ in 0..OPERATION_LIMIT {
        // let mut dist_max = -1;
        // let mut i = 0;
        // let mut j = 0;
        // for ii in 0..(n - 1) {
        //     let (ai, bi) = ab[ii];
        //     for jj in (ii + 1)..n {
        //         let (aj, bj) = ab[jj];
        //         let dist = (ai - aj).abs().max((bi - bj).abs());
        //         if dist > dist_max {
        //             dist_max = dist;
        //             i = ii;
        //             j = jj
        //         }
        //     }
        // }
        let (i, j) = (0..n - 1)
            .into_iter()
            .map(|i| {
                let (dist, j) = (i + 1..n)
                    .into_iter()
                    .map(|j| {
                        let (ai, bi) = ab[i];
                        let (aj, bj) = ab[j];
                        let dist = ai.abs_diff(aj).max(bi.abs_diff(bj));
                        (dist, j)
                    })
                    .max()
                    .unwrap();
                (dist, (i, j))
            })
            .max()
            .unwrap()
            .1;
        ans.push((i, j));
        operatioin(i, j, &mut ab);
    }
    ans
}

fn find_best(ab: &[(i64, i64)], ignore_idx: &mut HashSet<usize>) {
    let (mut a_sum, mut b_sum) = (0, 0);
    for &(a, b) in ab {
        a_sum -= TARGET;
        a_sum += a;
        b_sum -= TARGET;
        b_sum += b;
    }
    let mut best_dist = i64::MAX;
    let mut best_idx = 1;
    for (i, &(a, b)) in ab.iter().enumerate() {
        if i == 0 {
            continue;
        }
        if ignore_idx.contains(&i) {
            continue;
        }
        let dist = (a_sum - a + TARGET).abs() + (b_sum - b + TARGET).abs();
        if dist < best_dist {
            best_dist = dist;
            best_idx = i;
        }
    }
    ignore_idx.insert(best_idx);
}

fn solver2(n: usize, mut ab: Vec<(i64, i64)>) -> Vec<(usize, usize)> {
    // 仲間外れを1枚決めて、それ以外で solver1 の要領で中心に寄る
    // 2段階に分けて2回それを行う

    let mut ans = vec![];
    let mut ignore_idx = HashSet::new();

    for loops in 0..50 {
        if loops % 10 == 0 {
            find_best(&ab, &mut ignore_idx);
        }
        let mut dist_max = -1;
        let mut i = 0;
        let mut j = 0;
        for ii in 0..(n - 1) {
            if ignore_idx.contains(&ii) {
                continue;
            }
            let (ai, bi) = ab[ii];
            for jj in (ii + 1)..n {
                if ignore_idx.contains(&jj) {
                    continue;
                }
                let (aj, bj) = ab[jj];
                let dist = (ai - aj).abs().max((bi - bj).abs());
                if dist > dist_max {
                    dist_max = dist;
                    i = ii;
                    j = jj
                }
            }
        }
        ans.push((i, j));
        operatioin(i, j, &mut ab);
    }
    ans
}

fn solver3(n: usize, mut ab: Vec<(i64, i64)>) -> Vec<(usize, usize)> {
    // 仲間外れを1枚決めて、それ以外で solver1 の要領で中心に寄る
    // 2段階に分けて2回それを行う
    // solver2ベースで48回おこない、最後の2回は全探索

    let mut ans = vec![];
    let mut ignore_idx = HashSet::new();

    for loops in 0..48 {
        if loops % 5 == 0 {
            find_best(&ab, &mut ignore_idx);
        }
        let mut dist_max = -1;
        let mut i = 0;
        let mut j = 0;
        for ii in 0..(n - 1) {
            if ignore_idx.contains(&ii) {
                continue;
            }
            let (ai, bi) = ab[ii];
            for jj in (ii + 1)..n {
                if ignore_idx.contains(&jj) {
                    continue;
                }
                let (aj, bj) = ab[jj];
                let dist = (ai - aj).abs().max((bi - bj).abs());
                if dist > dist_max {
                    dist_max = dist;
                    i = ii;
                    j = jj
                }
            }
        }
        ans.push((i, j));
        operatioin(i, j, &mut ab);
    }

    // ここから最後の2回を全探索. 脳筋実装.
    // こういうのをAIでいい感じにするべき
    let (mut best_i0, mut best_i1, mut best_i2, mut best_i3) = (1, 2, 3, 4);
    let mut best_dist = {
        let &(a, b) = &ab[0];
        ((a - TARGET).abs()).max((b - TARGET).abs())
    };
    for i0 in 0..(n - 1) {
        for i1 in (i0 + 1)..n {
            let a0 = (&ab[i0].0 + &ab[i1].0) / 2;
            let b0 = (&ab[i0].1 + &ab[i1].1) / 2;
            let i2 = 0;
            for i3 in 1..n {
                if i0 == i2 {
                    if i1 == i3 {
                        let dist = ((a0 - TARGET).abs()).max((b0 - TARGET).abs());
                        if dist < best_dist {
                            best_dist = dist;
                            best_i0 = i0;
                            best_i1 = i1;
                            best_i2 = i2;
                            best_i3 = i3;
                        }
                    } else {
                        let dist = ((a0 + &ab[i3].0) / 2 - TARGET)
                            .abs()
                            .max(((b0 + &ab[i3].1) / 2 - TARGET).abs());
                        if dist < best_dist {
                            best_dist = dist;
                            best_i0 = i0;
                            best_i1 = i1;
                            best_i2 = i2;
                            best_i3 = i3;
                        }
                    }
                } else {
                    let mut dist = 0;
                    if i0 == i3 || i1 == i3 {
                        dist = ((a0 + &ab[i2].0) / 2 - TARGET)
                            .abs()
                            .max(((b0 + &ab[i2].1) / 2 - TARGET).abs());
                    } else {
                        dist = ((&ab[i2].0 + &ab[i3].0) / 2 - TARGET)
                            .abs()
                            .max(((&ab[i2].1 + &ab[i3].1) / 2 - TARGET).abs());
                    }
                    if dist < best_dist {
                        best_dist = dist;
                        best_i0 = i0;
                        best_i1 = i1;
                        best_i2 = i2;
                        best_i3 = i3;
                    }
                }
            }
        }
    }
    ans.push((best_i0, best_i1));
    ans.push((best_i2, best_i3));
    ans
}

fn solver4(n: usize, mut ab: Vec<(i64, i64)>) -> Vec<(usize, usize)> {
    // 仲間外れを決めるのはおなじ
    // ペアは必ず0とのペアとする

    let mut ans = vec![];
    let mut ignore_idx = HashSet::new();

    for loops in 0..48 {
        if loops % 3 == 0 {
            find_best(&ab, &mut ignore_idx);
        }
        let mut dist_max = -1;
        let mut i = 0;
        let mut j = 0;

        let (ai, bi) = ab[0];
        for jj in 1..n {
            if ignore_idx.contains(&jj) {
                continue;
            }
            let (aj, bj) = ab[jj];
            let dist = (ai - aj).abs().max((bi - bj).abs());
            if dist > dist_max {
                dist_max = dist;
                j = jj
            }
        }
        ans.push((i, j));
        operatioin(i, j, &mut ab);
    }

    // ここから最後の2回を全探索. 脳筋実装.
    // こういうのをAIでいい感じにするべき
    let (mut best_i0, mut best_i1, mut best_i2, mut best_i3) = (1, 2, 3, 4);
    let mut best_dist = {
        let &(a, b) = &ab[0];
        ((a - TARGET).abs()).max((b - TARGET).abs())
    };
    for i0 in 0..(n - 1) {
        for i1 in (i0 + 1)..n {
            let a0 = (&ab[i0].0 + &ab[i1].0) / 2;
            let b0 = (&ab[i0].1 + &ab[i1].1) / 2;
            let i2 = 0;
            for i3 in 1..n {
                if i0 == i2 {
                    if i1 == i3 {
                        let dist = ((a0 - TARGET).abs()).max((b0 - TARGET).abs());
                        if dist < best_dist {
                            best_dist = dist;
                            best_i0 = i0;
                            best_i1 = i1;
                            best_i2 = i2;
                            best_i3 = i3;
                        }
                    } else {
                        let dist = ((a0 + &ab[i3].0) / 2 - TARGET)
                            .abs()
                            .max(((b0 + &ab[i3].1) / 2 - TARGET).abs());
                        if dist < best_dist {
                            best_dist = dist;
                            best_i0 = i0;
                            best_i1 = i1;
                            best_i2 = i2;
                            best_i3 = i3;
                        }
                    }
                } else {
                    let mut dist = 0;
                    if i0 == i3 || i1 == i3 {
                        dist = ((a0 + &ab[i2].0) / 2 - TARGET)
                            .abs()
                            .max(((b0 + &ab[i2].1) / 2 - TARGET).abs());
                    } else {
                        dist = ((&ab[i2].0 + &ab[i3].0) / 2 - TARGET)
                            .abs()
                            .max(((&ab[i2].1 + &ab[i3].1) / 2 - TARGET).abs());
                    }
                    if dist < best_dist {
                        best_dist = dist;
                        best_i0 = i0;
                        best_i1 = i1;
                        best_i2 = i2;
                        best_i3 = i3;
                    }
                }
            }
        }
    }
    ans.push((best_i0, best_i1));
    ans.push((best_i2, best_i3));
    ans
}

fn main() {
    input! {
        n:usize,
        ab:[(i64, i64); n]
    }
    // solve
    let ans = solver4(n, ab.clone());
    eprintln!("{}", calc_score(ab.clone(), &ans));
    println!("{}", ans.len());
    for &(u, v) in &ans {
        println!("{} {}", u + 1, v + 1);
    }
}
0