提出 #36658214


ソースコード 拡げる

#![allow(non_snake_case)]

use itertools::Itertools;
use proconio::{source::line::LineSource, *};
use rand::prelude::*;
use std::{
    collections::HashMap,
    io::{prelude::*, BufReader, Stdin},
};

fn main() {
    get_time();
    let mut stdin = proconio::source::line::LineSource::new(std::io::BufReader::new(std::io::stdin()));
    let input = read_input(&mut stdin);
    if input.eps == 0.0 {
        solve_exact(&input, stdin);
    } else {
        let e = (input.eps * 100.0).round() as usize - 1;
        let m = (input.M - 8) / 3;
        let (ty, N) = STRATEGY[e][m];
        eprintln!("type = {}, N = {}", ty, N);
        if ty == 0 {
            solve_small(&input, stdin, N);
        } else {
            solve_large(&input, stdin, N);
        }
    }
    eprintln!("Time = {:.3}", get_time());
}

/// eps=0 用。
/// 完全一致を調べるだけ。
fn solve_exact(input: &Input, mut stdin: LineSource<BufReader<Stdin>>) {
    let N = if input.M <= 11 {
        4
    } else if input.M <= 34 {
        5
    } else {
        6
    };
    let mut G = vec![];
    find_all_graphs(&mut mat![false; N; N], 0, 1, &mut G);
    G.truncate(input.M);
    println!("{}", N);
    for k in 0..input.M {
        println!("{}", G[k]);
    }
    std::io::stdout().flush().unwrap();
    let mut map = HashMap::new();
    for k in 0..input.M {
        for g in find_all_perms(&str_to_graph(&G[k], N)) {
            map.insert(g, k);
        }
    }
    for _ in 0..Q {
        input! {
            from &mut stdin,
            h: String
        }
        let id = u64::from_str_radix(&h, 2).unwrap();
        println!("{}", map[&id]);
        std::io::stdout().flush().unwrap();
    }
}

/// 頂点数Nのラベルなしグラフを全列挙する
fn find_all_graphs(g: &mut Vec<Vec<bool>>, i: usize, j: usize, list: &mut Vec<String>) {
    let N = g.len();
    if i == N {
        let mut vs = (0..N).collect::<Vec<_>>();
        'lp: while next_permutation(&mut vs) {
            for i in 0..N {
                for j in 0..N {
                    if g[vs[i]][vs[j]] > g[i][j] {
                        continue 'lp;
                    } else if g[vs[i]][vs[j]] < g[i][j] {
                        return;
                    }
                }
            }
        }
        list.push(graph_to_str(g));
    } else if j == N {
        find_all_graphs(g, i + 1, i + 2, list);
    } else {
        find_all_graphs(g, i, j + 1, list);
        g[i][j] = true;
        g[j][i] = true;
        find_all_graphs(g, i, j + 1, list);
        g[i][j] = false;
        g[j][i] = false;
    }
}

/// グラフの頂点に番号を降った隣接行列表現を全列挙する
fn find_all_perms(g: &Vec<Vec<bool>>) -> Vec<u64> {
    let N = g.len();
    let mut vs = (0..N).collect::<Vec<_>>();
    let mut list = vec![];
    loop {
        let mut id = 0u64;
        for i in 0..N {
            for j in i + 1..N {
                id <<= 1;
                if g[vs[i]][vs[j]] {
                    id |= 1;
                }
            }
        }
        list.push(id);
        if !next_permutation(&mut vs) {
            break;
        }
    }
    list.sort();
    list.dedup();
    list
}

/// epsが小さい時用。
/// P(G[s]|H)=P(H|G[s])P(G[s])/P(H)~P(H|G[s]) なので、
/// G[s]からHが生成される確率P(H|G[s])が一番高いもとを選択するのが理論的に最適。
/// Nが小さい場合はこれが厳密に計算出来るので厳密計算して一番高いsを求める。
fn solve_small(input: &Input, mut stdin: LineSource<BufReader<Stdin>>, N: usize) {
    let mut G = vec![];
    for g in get_repr(input.eps, input.M, N) {
        G.push(int_to_graph(g, N));
    }
    println!("{}", N);
    for k in 0..input.M {
        println!("{}", graph_to_str(&G[k]));
    }
    std::io::stdout().flush().unwrap();

    // 2つのラベル付きGとHで異なる辺の個数をd(G,H)と表すと、
    // P(H|G)~Σ_π(ε^d(π(G),H)×(1-ε)^(N(N-1)/2-d(π(G),H)))
    // と計算できるので、予めπ(G)を列挙しておく(高速化のため重複は除去)
    let mut perms = vec![];
    for k in 0..input.M {
        perms.push(find_all_perms(&G[k]));
    }
    let mut es = vec![0.0; N * (N - 1) / 2 + 1];
    for i in 0..es.len() {
        es[i] = input.eps.powi(i as i32) * (1.0 - input.eps).powi((N * (N - 1) / 2 - i) as i32);
    }
    for _ in 0..Q {
        input! {
            from &mut stdin,
            h: String
        }
        let id = u64::from_str_radix(&h, 2).unwrap();
        let mut t = 0;
        let mut max = 0.0;
        for k in 0..input.M {
            let mut sum = 0.0;
            for &g in &perms[k] {
                sum += es[(g ^ id).count_ones() as usize];
            }
            if max.setmax(sum / perms[k].len() as f64) {
                t = k;
            }
        }
        println!("{}", t);
        std::io::stdout().flush().unwrap();
    }
}

// epsが大きい時用。
// ベースとなる頂点数5のグラフをM個用意し、それをD倍に冗長化する。
// 焼き鈍しでHの頂点のクラスタリングをして1/D倍に縮小し、各ベースグラフとの一致具合を調べる。
// D倍にするとベースグラフの頂点を孤立点にするかクリークにするかの選択肢も生じるため、ベースグラフは自己閉路ありとしている。
fn solve_large(input: &Input, mut stdin: LineSource<BufReader<Stdin>>, D: usize) {
    const N1: usize = 5;
    let N = N1 * D;
    let bases = get_bases(input.eps, input.M);
    let mut adjust = vec![];
    let mut G = vec![];
    for &b in &bases {
        let mut h = mat![false; N; N];
        let mut p = 0;
        let mut tmp = vec![0; N1];
        for i in 0..N1 {
            for j in i..N1 {
                if b >> p & 1 != 0 {
                    tmp[i] |= 1 << j;
                    tmp[j] |= 1 << i;
                    for x in 0..D {
                        for y in 0..D {
                            if i * D + x != j * D + y {
                                h[i * D + x][j * D + y] = true;
                                h[j * D + y][i * D + x] = true;
                            }
                        }
                    }
                }
                p += 1;
            }
        }
        G.push(h);
        tmp.sort();
        // 同じ行がある場合にグループ化の自由度が上る分だけHを生成できる確率が高くなるのでその補正
        let mut s = 0;
        let mut add = 0.0;
        while s < N1 {
            let mut t = s;
            while t < N1 && tmp[t] == tmp[s] {
                t += 1;
            }
            for i in 2..=(t - s) * D {
                add += f64::ln(i as f64);
            }
            for i in 2..=(t - s) {
                add -= f64::ln(i as f64);
            }
            s = t;
        }
        // そのまま足すと大きすぎたので0.5倍している
        adjust.push(add * 0.5);
    }
    println!("{}", N);
    for k in 0..input.M {
        println!("{}", graph_to_str(&G[k]));
    }
    std::io::stdout().flush().unwrap();
    let mut perms = vec![];
    for k in 0..input.M {
        let mut vs = (0..N1).collect::<Vec<_>>();
        let mut list = vec![];
        loop {
            let mut p = 0;
            let mut g = mat![false; N1; N1];
            for i in 0..N1 {
                for j in i..N1 {
                    if bases[k] >> p & 1 != 0 {
                        g[vs[i]][vs[j]] = true;
                        g[vs[j]][vs[i]] = true;
                    }
                    p += 1;
                }
            }
            let mut id = 0;
            p = 0;
            for i in 0..N1 {
                for j in i..N1 {
                    if g[i][j] {
                        id |= 1 << p;
                    }
                    p += 1;
                }
            }
            list.push(id);
            if !next_permutation(&mut vs) {
                break;
            }
        }
        list.sort();
        list.dedup();
        perms.push(list);
    }

    let mut rng = rand_pcg::Pcg64Mcg::seed_from_u64(432908);
    let stime = get_time();
    for q in 0..Q {
        input! {
            from &mut stdin,
            h: String
        }
        let H = str_to_graph(&h, N);
        let until = stime + (4.95 - stime) * (q + 1) as f64 / Q as f64;
        let t = estimate(input.eps, input.M, D, N1, &perms, &adjust, H, until, &mut rng);
        println!("{}", t);
        std::io::stdout().flush().unwrap();
    }
}

/// P(H|G[s])を計算するために全ての置換を試すわけにはいかないため、
/// 5つのグループへの頂点の分割を何通りか計算し、グループの置換を全通り試す。
/// 分割を決める問題がmin(x,c-x)の和の最小化という形で非常に非凸度が高く、一発で最適解に到達するのが困難なため、
/// 初期解を別の焼き鈍し易い形の問題を解くことで得て、そこから再度焼き鈍している。
fn estimate(
    eps: f64,
    M: usize,
    D: usize,
    N1: usize,
    perms: &Vec<Vec<i32>>,
    adjust: &Vec<f64>,
    H: Vec<Vec<bool>>,
    until: f64,
    rng: &mut rand_pcg::Pcg64Mcg,
) -> usize {
    let N = N1 * D;
    let rep = 15.0;
    // 確率が非常に小さくなるため、logを取って計算する
    let ln1 = f64::ln(1.0 - eps);
    let ln2 = f64::ln(eps);
    let mut probs = vec![std::f64::NEG_INFINITY; M];
    while get_time() < until {
        // 一段階目の焼き鈍し
        // グループ内の各ベクトルのハミング距離の和を最小化
        let mut h = vec![0u128; N];
        for i in 0..N {
            for j in 0..N {
                if H[i][j] {
                    h[i] |= 1 << j;
                }
            }
        }
        let mut diff = mat![0; N; N];
        for i in 0..N {
            for j in 0..N {
                diff[i][j] = (h[i] ^ h[j]).count_ones() as i32;
            }
        }
        let mut ps = vec![!0; N];
        for i in 0..N {
            ps[i] = i / D;
        }
        let mut vs = vec![vec![]; N1];
        for i in 0..N {
            vs[ps[i]].push(i);
        }
        let mut crt = 0;
        for i in 0..N1 {
            for a in 0..D {
                for b in a + 1..D {
                    crt += diff[vs[i][a]][vs[i][b]];
                }
            }
        }
        let mut best = crt;
        let mut best_ps = ps.clone();
        let stime = get_time();
        let TL = 0.01 / rep;
        let T0: f64 = (N * D) as f64;
        let T1: f64 = 1.0;
        let mut T = T0;
        for iter in 0.. {
            if iter & 31 == 0 {
                let t = (get_time() - stime) / TL;
                if t >= 1.0 {
                    break;
                }
                T = T0.powf(1.0 - t) * T1.powf(t);
            }
            let i = rng.gen_range(0, N1);
            let j = rng.gen_range(0, N1);
            if i == j {
                continue;
            }
            let a = rng.gen_range(0, D);
            let b = rng.gen_range(0, D);
            let mut next = crt;
            for c in 0..D {
                if c != a {
                    next -= diff[vs[i][a]][vs[i][c]];
                    next += diff[vs[j][b]][vs[i][c]];
                }
                if c != b {
                    next -= diff[vs[j][b]][vs[j][c]];
                    next += diff[vs[i][a]][vs[j][c]];
                }
            }
            if crt >= next || rng.gen_bool(f64::exp((crt - next) as f64 / T)) {
                crt = next;
                let tmp = vs[i][a];
                vs[i][a] = vs[j][b];
                vs[j][b] = tmp;
                if best.setmin(crt) {
                    for k in 0..N1 {
                        for h in 0..D {
                            best_ps[vs[k][h]] = k;
                        }
                    }
                }
            }
        }
        ps = best_ps;

        // ニ段階目の焼き鈍し
        // 各ブロックごとに0と1の近い方までの距離の和を最小化
        let mut H2 = mat![0; N; N1];
        let mut count = mat![0; N1; N1];
        for i in 0..N {
            for j in i + 1..N {
                if H[i][j] {
                    count[ps[i].min(ps[j])][ps[i].max(ps[j])] += 1;
                    H2[i][ps[j]] += 1;
                    H2[j][ps[i]] += 1;
                }
            }
        }
        let mut crt = 0;
        for i in 0..N1 {
            for j in i..N1 {
                let m = if i == j { D * (D - 1) / 2 } else { D * D } as i32;
                crt += count[i][j].min(m - count[i][j]);
            }
        }
        let mut best = crt;
        let mut best_ps = ps.clone();
        let stime = get_time();
        let TL = 0.03 / rep;
        // 良い感じの初期解があるので温度は低め
        let T0: f64 = 5.0;
        let T1: f64 = 1.0;
        let mut T = T0;
        for iter in 0.. {
            if iter & 31 == 0 {
                let t = (get_time() - stime) / TL;
                if t >= 1.0 {
                    break;
                }
                T = T0.powf(1.0 - t) * T1.powf(t);
            }
            let i = rng.gen_range(0, N);
            let j = rng.gen_range(0, N);
            if ps[i] == ps[j] {
                continue;
            }
            for k in 0..N1 {
                count[ps[i].min(k)][ps[i].max(k)] -= H2[i][k];
                count[ps[j].min(k)][ps[j].max(k)] -= H2[j][k];
            }
            if H[i][j] {
                count[ps[j].min(ps[i])][ps[j].max(ps[i])] += 1;
            }
            ps.swap(i, j);
            for k in 0..N1 {
                count[ps[i].min(k)][ps[i].max(k)] += H2[i][k];
                count[ps[j].min(k)][ps[j].max(k)] += H2[j][k];
            }
            if H[i][j] {
                count[ps[i].min(ps[j])][ps[i].max(ps[j])] += 1;
                count[ps[i]][ps[i]] -= 1;
                count[ps[j]][ps[j]] -= 1;
            }
            let mut next = 0;
            for i in 0..N1 {
                for j in i..N1 {
                    let m = if i == j { D * (D - 1) / 2 } else { D * D } as i32;
                    next += count[i][j].min(m - count[i][j]);
                }
            }
            if crt >= next || rng.gen_bool(f64::exp((crt - next) as f64 / T)) {
                crt = next;
                if best.setmin(crt) {
                    best_ps = ps.clone();
                }
                for k in 0..N {
                    if H[i][k] {
                        H2[k][ps[j]] -= 1;
                        H2[k][ps[i]] += 1;
                    }
                    if H[j][k] {
                        H2[k][ps[i]] -= 1;
                        H2[k][ps[j]] += 1;
                    }
                }
            } else {
                for k in 0..N1 {
                    count[ps[i].min(k)][ps[i].max(k)] -= H2[i][k];
                    count[ps[j].min(k)][ps[j].max(k)] -= H2[j][k];
                }
                if H[i][j] {
                    count[ps[i].min(ps[j])][ps[i].max(ps[j])] -= 1;
                    count[ps[i]][ps[i]] += 1;
                    count[ps[j]][ps[j]] += 1;
                }
                ps.swap(i, j);
                for k in 0..N1 {
                    count[ps[i].min(k)][ps[i].max(k)] += H2[i][k];
                    count[ps[j].min(k)][ps[j].max(k)] += H2[j][k];
                }
                if H[i][j] {
                    count[ps[j].min(ps[i])][ps[j].max(ps[i])] -= 1;
                }
            }
        }
        ps = best_ps;

        let mut count = mat![0; N1; N1];
        for i in 0..N {
            for j in i + 1..N {
                if H[i][j] {
                    count[ps[i].min(ps[j])][ps[i].max(ps[j])] += 1;
                }
            }
        }
        // G[k]の各置換に対してHの生成確率を計算
        for k in 0..M {
            let mut sum = std::f64::NEG_INFINITY;
            for &g in &perms[k] {
                let mut prob = 0.0;
                let mut p = 0;
                for i in 0..N1 {
                    for j in i..N1 {
                        let c = count[i][j];
                        let m = if i == j { D * (D - 1) / 2 } else { D * D };
                        if g >> p & 1 != 0 {
                            prob += c as f64 * ln1 + (m - c) as f64 * ln2;
                        } else {
                            prob += (m - c) as f64 * ln1 + c as f64 * ln2;
                        }
                        p += 1;
                    }
                }
                sum = ln_add_exp(sum, prob);
            }
            probs[k] = ln_add_exp(probs[k], sum + adjust[k] - (perms[k].len() as f64).ln());
        }
    }
    let mut t = 0;
    for k in 0..M {
        if probs[t] < probs[k] {
            t = k;
        }
    }
    t
}

// 入出力と得点計算

const Q: usize = 100;

#[derive(Clone, Debug)]
struct Input {
    M: usize,
    eps: f64,
}

fn read_input(f: &mut LineSource<BufReader<Stdin>>) -> Input {
    input! {
        from f,
        M: usize, eps: f64
    }
    Input { M, eps }
}

fn str_to_graph(s: &str, N: usize) -> Vec<Vec<bool>> {
    let s = s.chars().collect::<Vec<_>>();
    let mut g = mat![false; N; N];
    let mut p = 0;
    for i in 0..N {
        for j in i + 1..N {
            if s[p] == '1' {
                g[i][j] = true;
                g[j][i] = true;
            }
            p += 1;
        }
    }
    g
}

fn int_to_graph(s: u64, N: usize) -> Vec<Vec<bool>> {
    str_to_graph(&format!("{:01$b}", s, N * (N - 1) / 2), N)
}

fn graph_to_str(g: &Vec<Vec<bool>>) -> String {
    let N = g.len();
    let mut s = String::new();
    for i in 0..N {
        for j in i + 1..N {
            s.push(if g[i][j] { '1' } else { '0' });
        }
    }
    s
}

// ここからライブラリ

pub trait SetMinMax {
    fn setmin(&mut self, v: Self) -> bool;
    fn setmax(&mut self, v: Self) -> bool;
}
impl<T> SetMinMax for T
where
    T: PartialOrd,
{
    fn setmin(&mut self, v: T) -> bool {
        *self > v && {
            *self = v;
            true
        }
    }
    fn setmax(&mut self, v: T) -> bool {
        *self < v && {
            *self = v;
            true
        }
    }
}

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

pub fn get_time() -> 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;
        }
        // ローカル環境とジャッジ環境の実行速度差はget_timeで吸収しておくと便利
        #[cfg(feature = "local")]
        {
            (ms - STIME) * 1.3
        }
        #[cfg(not(feature = "local"))]
        {
            ms - STIME
        }
    }
}

pub fn next_permutation<T>(a: &mut [T]) -> bool
where
    T: PartialOrd,
{
    let n = a.len();
    for i in (1..n).rev() {
        if a[i - 1] < a[i] {
            let mut j = n - 1;
            while a[i - 1] >= a[j] {
                j -= 1;
            }
            a.swap(i - 1, j);
            a[i..n].reverse();
            return true;
        }
    }
    a.reverse();
    false
}

/// ln(exp(a)+exp(b))
fn ln_add_exp(a: f64, b: f64) -> f64 {
    if a < b {
        ln_add_exp(b, a)
    } else {
        a + (b - a).exp().ln_1p()
    }
}

// ここから前計算データ

#[rustfmt::skip]
/// 各epsとM(3刻み)のペアについて、どの方式とNのサイズを使うとよいかを予め決めておいたもの
/// 方式0(solve_small): 小さいeps用で指定されたNの値を使用
/// 方式1(solve_large): 大きいeps用で5点のグラフを指定されたDの値だけ冗長化(N=5D)
const STRATEGY: [[(i32, usize); 31]; 40] = [
    [(0, 6), (0, 6), (0, 6), (0, 6), (0, 6), (0, 6), (0, 6), (0, 6), (0, 6), (0, 6), (0, 7), (0, 7), (0, 7), (0, 7), (0, 7), (0, 7), (0, 7), (0, 7), (0, 7), (0, 7), (0, 7), (0, 7), (0, 7), (0, 7), (0, 7), (0, 7), (0, 7), (0, 7), (0, 7), (0, 8), (0, 8), ],
    [(0, 6), (0, 6), (0, 6), (0, 6), (0, 7), (0, 7), (0, 7), (0, 7), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 9), ],
    [(0, 6), (0, 6), (0, 7), (0, 7), (0, 7), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), ],
    [(0, 6), (0, 7), (0, 7), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 8), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), ],
    [(0, 7), (0, 7), (0, 8), (0, 8), (0, 8), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), ],
    [(0, 7), (0, 8), (0, 8), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), ],
    [(0, 8), (0, 8), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), ],
    [(0, 8), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), ],
    [(0, 8), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 4), (1, 4), (1, 4), (1, 4), ],
    [(0, 9), (0, 9), (0, 9), (0, 9), (0, 9), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 3), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), ],
    [(0, 9), (0, 9), (0, 9), (0, 9), (1, 3), (1, 3), (1, 3), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), ],
    [(0, 9), (0, 9), (0, 9), (1, 3), (1, 3), (1, 3), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), ],
    [(0, 9), (0, 9), (1, 3), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), ],
    [(0, 9), (0, 9), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 5), (1, 5), (1, 5), ],
    [(0, 9), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), ],
    [(1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), ],
    [(1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 4), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), ],
    [(1, 4), (1, 4), (1, 4), (1, 4), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 6), ],
    [(1, 4), (1, 4), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), ],
    [(1, 4), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), ],
    [(1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), ],
    [(1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), ],
    [(1, 5), (1, 5), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), ],
    [(1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 8), (1, 8), ],
    [(1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 6), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), ],
    [(1, 6), (1, 6), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 7), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), ],
    [(1, 6), (1, 6), (1, 7), (1, 7), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 9), (1, 9), (1, 9), (1, 9), (1, 9), (1, 9), (1, 9), (1, 9), (1, 9), (1, 9), (1, 9), (1, 9), (1, 9), (1, 9), ],
    [(1, 6), (1, 7), (1, 7), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 9), (1, 9), (1, 9), (1, 9), (1, 9), (1, 9), (1, 9), (1, 9), (1, 9), (1, 9), (1, 9), (1, 9), (1, 9), (1, 9), (1, 9), (1, 9), (1, 9), (1, 10), (1, 10), ],
    [(1, 7), (1, 7), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 8), (1, 9), (1, 9), (1, 9), (1, 9), (1, 9), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), ],
    [(1, 7), (1, 8), (1, 9), (1, 9), (1, 9), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 11), (1, 11), (1, 11), (1, 11), (1, 11), (1, 11), (1, 11), (1, 11), (1, 11), (1, 11), (1, 11), (1, 11), (1, 11), ],
    [(1, 7), (1, 8), (1, 9), (1, 9), (1, 9), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 11), (1, 11), (1, 11), (1, 11), (1, 11), (1, 11), (1, 11), (1, 11), (1, 11), (1, 11), (1, 12), (1, 12), (1, 12), (1, 12), (1, 12), (1, 12), (1, 12), (1, 12), (1, 13), ],
    [(1, 8), (1, 9), (1, 9), (1, 9), (1, 10), (1, 10), (1, 10), (1, 10), (1, 10), (1, 11), (1, 11), (1, 11), (1, 12), (1, 12), (1, 12), (1, 12), (1, 12), (1, 12), (1, 12), (1, 13), (1, 13), (1, 13), (1, 13), (1, 13), (1, 14), (1, 14), (1, 14), (1, 14), (1, 14), (1, 14), (1, 14), ],
    [(1, 8), (1, 10), (1, 10), (1, 10), (1, 11), (1, 11), (1, 11), (1, 12), (1, 12), (1, 12), (1, 12), (1, 13), (1, 13), (1, 13), (1, 13), (1, 13), (1, 13), (1, 13), (1, 13), (1, 14), (1, 14), (1, 14), (1, 14), (1, 14), (1, 14), (1, 15), (1, 15), (1, 15), (1, 15), (1, 15), (1, 15), ],
    [(1, 10), (1, 11), (1, 11), (1, 11), (1, 11), (1, 12), (1, 13), (1, 13), (1, 13), (1, 13), (1, 13), (1, 14), (1, 14), (1, 14), (1, 15), (1, 15), (1, 15), (1, 15), (1, 15), (1, 15), (1, 16), (1, 16), (1, 16), (1, 16), (1, 16), (1, 16), (1, 17), (1, 17), (1, 17), (1, 17), (1, 17), ],
    [(1, 11), (1, 11), (1, 12), (1, 12), (1, 13), (1, 13), (1, 14), (1, 14), (1, 14), (1, 14), (1, 14), (1, 15), (1, 15), (1, 15), (1, 15), (1, 16), (1, 16), (1, 16), (1, 17), (1, 18), (1, 18), (1, 18), (1, 18), (1, 18), (1, 18), (1, 18), (1, 18), (1, 18), (1, 18), (1, 19), (1, 19), ],
    [(1, 13), (1, 13), (1, 13), (1, 15), (1, 15), (1, 15), (1, 15), (1, 16), (1, 16), (1, 16), (1, 16), (1, 18), (1, 18), (1, 18), (1, 18), (1, 18), (1, 19), (1, 19), (1, 19), (1, 19), (1, 19), (1, 19), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), ],
    [(1, 14), (1, 15), (1, 15), (1, 15), (1, 15), (1, 17), (1, 17), (1, 17), (1, 18), (1, 19), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), ],
    [(1, 14), (1, 18), (1, 18), (1, 18), (1, 19), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), ],
    [(1, 15), (1, 18), (1, 19), (1, 19), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), ],
    [(1, 19), (1, 19), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), (1, 20), ],
];

// solve_large用の前計算データ
// 冗長化まえの5頂点のグラフで正解確率が高くなりそうなのを予め計算
// 計算方法: 実際にシミュレーションし、一番不正解の多かったグラフを別のグラフに入れ替える山登りをした
// (eps, M)のペア何通りかについて用意したけど1つ固定でもそこまで変わらない

// 0.013, D=4
const GRAPH_12_100: [i32; 100] = [
    30918, 9410, 10374, 31975, 11841, 32192, 11974, 31399, 13410, 27843, 11398, 15822, 3170, 16384, 31366, 10466, 24770, 30307,
    28256, 27682, 9667, 8642, 30434, 32707, 30403, 3650, 13762, 32483, 30305, 25826, 11875, 32358, 3526, 10432, 25667, 11457,
    27714, 28126, 16065, 9250, 28326, 30913, 29280, 26176, 9698, 10435, 28227, 28737, 31814, 3137, 13312, 26851, 27982, 12262,
    28102, 32199, 27713, 28039, 31746, 29410, 32450, 32390, 15554, 29154, 31811, 31840, 25600, 29729, 20390, 20032, 32289, 25539,
    32742, 27712, 11654, 30915, 30178, 29667, 32355, 32705, 11456, 28550, 29730, 16006, 28494, 32706, 32322, 30304, 27746, 25698,
    29216, 32134, 15586, 29634, 30914, 29763, 29281, 16866, 31846, 19846,
];

// 0.008, D=6
const GRAPH_20_100: [i32; 100] = [
    30918, 0, 32734, 10432, 31399, 31366, 31846, 25667, 31746, 25600, 13410, 32199, 12262, 9250, 30913, 11974, 29280, 16038,
    11456, 32192, 25698, 28039, 27875, 20032, 27682, 29729, 27842, 30915, 32288, 28737, 11875, 16064, 32707, 15554, 13346, 32483,
    20390, 30434, 28550, 30305, 28102, 28227, 27714, 9698, 26176, 25539, 29378, 29154, 16067, 3137, 30403, 16366, 27746, 3974,
    8642, 31811, 10374, 9410, 27747, 3170, 25826, 28494, 27982, 30306, 3650, 32326, 28225, 32742, 32450, 31878, 9667, 26851,
    32359, 8674, 10466, 10435, 32193, 30307, 16006, 24770, 30304, 13762, 27713, 26758, 29184, 32355, 3649, 30402, 31937, 27744,
    10467, 27712, 32739, 29667, 13763, 13506, 27782, 11457, 3138, 32390,
];

// 0.013, D=11
const GRAPH_30_100: [i32; 100] = [
    0, 32767, 28672, 32256, 16366, 482, 29249, 11598, 450, 31846, 29122, 10432, 32359, 31746, 3649, 13346, 4070, 32198, 9250,
    29280, 16067, 32707, 32192, 3136, 29378, 15554, 32738, 11457, 12110, 10433, 10435, 16065, 32483, 3974, 32193, 28039, 16064,
    30306, 10466, 32739, 3648, 13410, 30305, 27746, 30915, 31810, 3526, 32134, 3682, 10467, 31811, 9698, 3137, 28550, 27713,
    9667, 13762, 13763, 3170, 3138, 28227, 27683, 29729, 32706, 27747, 32450, 25667, 30918, 32322, 28225, 32355, 30913, 11456,
    32199, 32326, 32352, 11974, 10374, 32291, 30434, 25539, 20390, 27875, 30402, 9666, 30435, 27782, 13506, 26758, 31398, 25826,
    31399, 30403, 32390, 27744, 31878, 31366, 16038, 26112, 26176,
];

// 0.011, D=15
const GRAPH_35_40: [i32; 40] = [
    0, 32767, 28672, 32739, 16366, 31847, 32290, 29282, 19846, 32737, 12110, 32706, 482, 32736, 10433, 450, 10432, 3526, 29281,
    4070, 32135, 3649, 31842, 10434, 28038, 32449, 32451, 32256, 3137, 13762, 10467, 19520, 25026, 31776, 16066, 28898, 29154,
    28102, 11462, 30178,
];

// 0.012, D=17
const GRAPH_35_70: [i32; 70] = [
    0, 32767, 450, 28672, 32256, 32737, 12110, 16366, 16064, 10433, 4070, 3462, 32736, 482, 11598, 29154, 10432, 32321, 32359,
    29281, 3526, 15553, 3649, 3136, 28898, 30306, 32738, 3170, 32135, 32706, 32354, 24770, 31847, 13346, 28738, 32739, 3648,
    16099, 29122, 16066, 32707, 3137, 10466, 32291, 32290, 29248, 32258, 32322, 9698, 15494, 27782, 16067, 11462, 29378, 32323,
    31809, 13763, 11456, 26851, 10467, 31811, 30146, 32134, 32198, 9666, 32451, 32352, 31814, 10374, 32646,
];

// 0.012, D=19
const GRAPH_35_100: [i32; 100] = [
    0, 32767, 450, 482, 28672, 32256, 32736, 32737, 11598, 12110, 32739, 16366, 16064, 29154, 29281, 10432, 10433, 3648, 32738,
    32135, 32706, 3170, 3649, 3137, 32322, 31847, 4070, 32321, 32707, 3136, 28898, 27782, 16067, 16066, 3526, 32354, 9666, 16099,
    29248, 29122, 11462, 32359, 24770, 32451, 3462, 32291, 15494, 10466, 26851, 9698, 10374, 32134, 13763, 31811, 29378, 10467,
    13346, 32290, 32323, 9410, 32352, 31814, 32646, 28738, 11456, 32258, 30146, 31809, 15553, 30306, 29763, 32450, 25667, 3974,
    27746, 32390, 13506, 30913, 13410, 11974, 29282, 32198, 9250, 3682, 11457, 9667, 4038, 29794, 30918, 27747, 32355, 32449,
    26758, 27842, 28770, 32353, 32289, 32358, 31975, 31366,
];

// 0.012, D=17
const GRAPH_36_40: [i32; 40] = [
    32767, 482, 16366, 12110, 3462, 31744, 16065, 32359, 450, 29154, 16384, 3136, 32736, 28672, 32737, 4038, 10467, 10432, 13762,
    28038, 29281, 11598, 16067, 10433, 3648, 3649, 32738, 32739, 32706, 32354, 32448, 24770, 32290, 29248, 32707, 32646, 29729,
    28259, 32323, 32291,
];

// 0.013, D=19
const GRAPH_36_70: [i32; 70] = [
    0, 32767, 32737, 32736, 450, 16366, 28672, 3136, 3648, 10432, 32359, 10433, 482, 29281, 11598, 12110, 28738, 3462, 32739,
    32738, 13346, 32258, 32135, 32706, 10466, 28038, 20454, 32646, 29154, 32707, 3649, 32288, 32450, 32355, 28898, 31842, 11398,
    13794, 32354, 31744, 31811, 16099, 29248, 13762, 31810, 32291, 4038, 3974, 32323, 25026, 3170, 26851, 3137, 32290, 24770,
    28225, 16067, 16064, 30307, 11462, 28224, 3138, 31847, 11457, 27713, 11974, 31846, 3526, 32451, 9666,
];

// 0.020, D=20
const GRAPH_36_100: [i32; 100] = [
    0, 32767, 482, 32737, 29281, 32736, 450, 16366, 10433, 11598, 12110, 32738, 32706, 32354, 28672, 28898, 29154, 32291, 3136,
    32739, 3462, 3649, 3648, 32707, 16099, 32448, 16067, 31744, 29248, 4038, 13762, 3137, 10432, 32323, 11398, 10466, 11462,
    3170, 32288, 32359, 13794, 20454, 3526, 13346, 24770, 28225, 31811, 31847, 32258, 32135, 28038, 26851, 32451, 25026, 31842,
    27713, 28224, 3138, 32290, 9410, 11457, 9666, 30307, 27714, 11974, 28550, 3974, 32450, 28738, 28770, 10467, 10434, 13506,
    10374, 29378, 15494, 29762, 30913, 29794, 25667, 16066, 26816, 32198, 30914, 13410, 31878, 13312, 31846, 32358, 30304, 10435,
    16065, 13763, 15554, 11456, 27747, 32352, 9250, 32449, 28039,
];

// 0.013, D=20
const GRAPH_37_40: [i32; 40] = [
    0, 32767, 450, 32737, 11598, 28672, 16366, 31744, 32355, 32134, 29281, 19846, 32359, 32736, 10433, 20454, 32739, 32290,
    32706, 32738, 31846, 26816, 3136, 3649, 28866, 32448, 25026, 16065, 16866, 31810, 16066, 13794, 28225, 29794, 11398, 20032,
    32289, 4038, 3137, 9667,
];

// 0.022, D=20
const GRAPH_37_70: [i32; 70] = [
    0, 32767, 28672, 16366, 32359, 32736, 482, 31744, 3648, 31847, 450, 32737, 11598, 10432, 10433, 32738, 31810, 32739, 13346,
    3649, 29281, 20454, 13794, 32321, 32354, 16065, 32448, 3136, 32134, 3462, 32706, 10434, 13762, 29282, 29634, 29154, 32288,
    32355, 10466, 4038, 29794, 3138, 29248, 28550, 32291, 3137, 32323, 11974, 32135, 9666, 28866, 27782, 3526, 30307, 16099,
    28494, 27713, 32450, 32707, 32290, 31811, 29410, 32258, 32451, 3974, 13506, 15494, 30914, 10467, 32353,
];

// 0.055, D=20
const GRAPH_37_100: [i32; 100] = [
    0, 32767, 32736, 450, 32737, 10432, 11598, 482, 28672, 3136, 16366, 10433, 32739, 3648, 29281, 32706, 3649, 4038, 29248,
    32738, 31744, 32291, 3462, 32355, 32290, 20454, 31810, 13794, 16065, 3974, 32288, 3137, 32354, 10466, 29154, 32135, 28494,
    32359, 32134, 10434, 32258, 28866, 32707, 3526, 32323, 27782, 28224, 31842, 16099, 11974, 3170, 13346, 31847, 3138, 32451,
    15494, 29282, 27713, 29729, 32450, 32358, 10374, 30306, 30914, 32646, 9698, 30307, 31846, 32448, 9666, 25026, 16067, 10467,
    29762, 30146, 9250, 26850, 29410, 13312, 16066, 9410, 28225, 32352, 11457, 16064, 30913, 13506, 10435, 32321, 13762, 15554,
    28646, 28770, 29122, 29763, 32353, 13410, 11875, 15555, 9667,
];

// 0.025, D=20
const GRAPH_38_40: [i32; 40] = [
    0, 32767, 16366, 28672, 3136, 482, 450, 11598, 3649, 32736, 32737, 29282, 10432, 32359, 16064, 32355, 10434, 32739, 28738,
    28550, 32738, 29281, 10433, 31810, 28866, 32354, 32321, 32706, 31808, 3462, 13794, 4070, 16065, 31847, 3974, 4038, 29634,
    29154, 29729, 13506,
];

// 0.056, D=20
const GRAPH_38_70: [i32; 70] = [
    0, 32767, 28672, 482, 16366, 450, 32736, 32359, 32705, 32134, 32738, 11598, 10433, 3136, 32448, 10466, 32706, 28770, 31847,
    13794, 3649, 29248, 32355, 31779, 28494, 16065, 32739, 32290, 10434, 30146, 32354, 4070, 20032, 29281, 28738, 28224, 3974,
    3462, 3526, 29122, 9666, 29154, 11974, 31744, 32258, 29730, 3137, 28102, 28898, 3138, 32707, 30914, 4038, 15554, 10432,
    28227, 11654, 32135, 28225, 3170, 31810, 11398, 32322, 26816, 31776, 30307, 11462, 27782, 32352, 27713,
];

// 0.119, D=20
const GRAPH_38_100: [i32; 100] = [
    0, 32767, 16366, 450, 32736, 32359, 32738, 11598, 28672, 3136, 32706, 32739, 482, 29281, 32355, 3649, 10433, 31847, 3974,
    28494, 3462, 4070, 3526, 29248, 10466, 28770, 32290, 10434, 29154, 16065, 10432, 32291, 28738, 13794, 4038, 32707, 32354,
    3137, 32258, 11462, 29122, 28898, 29730, 3138, 11398, 28224, 13312, 28227, 26816, 28102, 31842, 32135, 30914, 9666, 31744,
    30146, 15554, 3170, 28550, 32448, 31776, 28225, 31810, 9698, 31811, 20032, 31809, 32451, 16099, 32134, 30307, 16064, 28038,
    32737, 32352, 11457, 24770, 16067, 29728, 32256, 32705, 8674, 27712, 31878, 26850, 15494, 13762, 28866, 10467, 10435, 27747,
    29762, 32353, 29763, 30304, 29634, 31938, 3648, 32321, 11875,
];

// 0.060, D=20
const GRAPH_39_40: [i32; 40] = [
    32767, 16366, 16866, 450, 28672, 32705, 32736, 31847, 3137, 31779, 16064, 31744, 12110, 3648, 10434, 29282, 20454, 32354,
    10433, 32134, 32321, 9666, 32738, 32739, 32706, 30178, 11598, 4038, 3974, 32258, 26816, 28738, 16066, 10466, 3526, 29728,
    29281, 31810, 28866, 11462,
];

// 0.144, D=20
const GRAPH_39_70: [i32; 70] = [
    32767, 16064, 28672, 25058, 32359, 12110, 450, 10434, 32738, 31744, 32706, 3649, 29282, 32736, 31779, 29248, 3462, 30178,
    32192, 30146, 16866, 31847, 4070, 32290, 9666, 12262, 20032, 32739, 32288, 32354, 10433, 11398, 16366, 32321, 3526, 10466,
    28738, 16065, 11654, 19520, 3974, 4038, 16066, 32134, 3138, 8642, 13312, 32707, 29281, 32705, 28550, 3137, 31810, 28259,
    10432, 27982, 32258, 26816, 30914, 11974, 11462, 31809, 0, 16067, 13346, 16334, 27712, 32737, 16384, 3682,
];

// 0.233, D=20
const GRAPH_39_100: [i32; 100] = [
    32767, 16064, 12110, 450, 28672, 16866, 32736, 32706, 3648, 32738, 32192, 4070, 30178, 31847, 3974, 32321, 4038, 3649, 10433,
    29281, 3138, 32134, 3137, 3526, 32288, 10434, 31744, 31779, 12262, 32290, 16366, 10466, 19520, 32739, 16066, 28738, 10432,
    28550, 32359, 32707, 30914, 11462, 30146, 26816, 31842, 29248, 13312, 25058, 29282, 11398, 29728, 28259, 32705, 9666, 0,
    16334, 32449, 16065, 32737, 32734, 16384, 32258, 29154, 31810, 13346, 32358, 28898, 11654, 27982, 27712, 11598, 3462, 32291,
    32742, 27682, 32256, 13506, 30304, 19846, 32451, 29122, 16067, 9216, 13762, 25026, 8642, 27782, 28770, 31878, 10435, 32323,
    29216, 27713, 28227, 32198, 11841, 10467, 32289, 31814, 10374,
];

// 0.138, D=20
const GRAPH_40_40: [i32; 40] = [
    0, 28672, 32767, 482, 10432, 450, 16334, 31779, 4070, 12110, 16064, 32258, 16065, 28770, 3137, 32706, 32359, 32705, 20032,
    31808, 32134, 19846, 29248, 32707, 32355, 3526, 9698, 32736, 10466, 32738, 3649, 4038, 11398, 3974, 29154, 28126, 32192,
    25026, 15554, 29122,
];

// 0.281, D=20
const GRAPH_40_70: [i32; 70] = [
    32767, 16366, 0, 32737, 28672, 10432, 450, 16064, 32706, 3462, 32290, 32736, 32192, 28770, 3649, 482, 12110, 31779, 4070,
    32359, 32355, 20032, 29154, 32738, 8704, 29122, 4038, 3974, 3138, 32707, 10435, 3526, 12262, 10466, 10433, 31847, 29248,
    28102, 29728, 9698, 31808, 32739, 29281, 11654, 27982, 13312, 28225, 32134, 9666, 31776, 3137, 8642, 11462, 30146, 16066,
    19520, 8674, 28038, 28738, 30914, 32256, 32291, 31744, 32449, 16067, 16070, 15553, 16065, 27746, 11974,
];

// 0.391, D=20
const GRAPH_40_100: [i32; 100] = [
    32767, 32736, 10432, 450, 32706, 482, 32738, 12110, 4070, 32359, 29122, 3526, 0, 20032, 3649, 3137, 3974, 16366, 9666, 32707,
    4038, 10433, 9698, 32739, 31779, 32737, 10466, 29154, 28770, 30146, 19520, 29248, 16064, 16065, 32355, 8642, 28738, 28102,
    8674, 10435, 29282, 32290, 31744, 10434, 32256, 28672, 16070, 31808, 3138, 29281, 32134, 3462, 13312, 31776, 29728, 32192,
    30914, 32705, 16384, 28038, 30178, 12262, 29184, 27982, 16066, 32291, 8704, 11462, 32449, 31847, 11598, 32222, 31811, 15822,
    19846, 32451, 32448, 32258, 11654, 28256, 3170, 3682, 16334, 32323, 11841, 8737, 32322, 31809, 28126, 13763, 31846, 25600,
    31842, 13538, 28646, 11430, 31878, 30306, 32353, 32289,
];

fn get_bases(eps: f64, M: usize) -> Vec<i32> {
    match (eps * 100.0f64).round() as i32 {
        a if a <= 12 => &GRAPH_12_100[..],
        a if a <= 20 => &GRAPH_20_100[..],
        a if a <= 30 => &GRAPH_30_100[..],
        a if a <= 35 && M <= 40 => &GRAPH_35_40[..],
        a if a <= 35 && M <= 70 => &GRAPH_35_70[..],
        a if a <= 35 => &GRAPH_35_100[..],
        36 if M <= 40 => &GRAPH_36_40[..],
        36 if M <= 70 => &GRAPH_36_70[..],
        36 => &GRAPH_36_100[..],
        37 if M <= 40 => &GRAPH_37_40[..],
        37 if M <= 70 => &GRAPH_37_70[..],
        37 => &GRAPH_37_100[..],
        38 if M <= 40 => &GRAPH_38_40[..],
        38 if M <= 70 => &GRAPH_38_70[..],
        38 => &GRAPH_38_100[..],
        39 if M <= 40 => &GRAPH_39_40[..],
        39 if M <= 70 => &GRAPH_39_70[..],
        39 => &GRAPH_39_100[..],
        40 if M <= 40 => &GRAPH_40_40[..],
        40 if M <= 70 => &GRAPH_40_70[..],
        40 => &GRAPH_40_100[..],
        _ => unimplemented!(),
    }
    .iter()
    .take(M)
    .cloned()
    .collect_vec()
}

// solve_small用の前計算データ
// 各N(6<=N<=9)に対して、最適なグラフ集合を前計算した
// 計算方法:
//   グラフGの隣接行列全体の集合をL(G)と表すことにする。
//   成功確率は少し式変形すると以下のように表される。
//   P(success)=1/M Σ_H max_s |L(H)|/|L(G[s])| Σ_{G'∈L(G[s])} ε^{d(H,G')}(1-ε)^(N(N-1)/2-d(H,G'))
//   N頂点のグラフはNが小さいので全列挙可能(N=8で12346, N=9で274668)。
//   小さいNで試すと対象性が高い(|L(G)|が小さい)ものしか使われなかったので、Gの候補はL(G)の小さいものに限定し、
//   p[H][G[s]] := Σ_{G'∈L(G[s])} ε^{d(H,G')}(1-ε)^(N(N-1)/2-d(H,G'))
//   を全ての(H,G[s])ペアについて計算しておく。
//   これでGの集合を変更したときの成功確率がHの総数くらいの計算時間で更新出来るようになるので焼き鈍すことが可能。

// eps=0.08 0.84099
const GRAPH9_8: [u64; 100] = [
    268435455, 68719476735, 4265133183, 4135458444, 0, 32767, 31965120, 1893965304, 832061473, 270566475, 811699423, 534739892,
    17045626360, 4058496990, 16540167, 8387558475, 1932864095, 274625312, 831519774, 8538791935, 1067348769, 7672, 811701612,
    33148158, 2000485296, 811728894, 834192491, 1895825400, 864972801, 66059500, 1936584481, 271040459, 4076051967, 270566516,
    4135485439, 31965183, 1895622256, 101599, 332880304, 8538791928, 1894573131, 817652228, 811767223, 1069479860, 1932864070,
    4143689440, 8387559423, 63, 1893986008, 271040500, 832077823, 14917113, 1937099998, 8387558636, 276756331, 33150580,
    8538935147, 811700000, 4058496967, 298269620, 2132566535, 871365855, 811725631, 4294967244, 6402816, 813694975, 255567,
    1936584198, 270567423, 838454527, 270600487, 811726708, 939507678, 935245643, 2134697589, 271546800, 4058496960, 281364628,
    830980062, 15060191, 17112219614, 270597045, 2097151, 833009476, 334495668, 6393054, 832569313, 811767216, 832230755,
    1067450366, 283352575, 299858816, 811710293, 271006655, 7916, 66568140, 1893983820, 4075680843, 2132569823, 4277923553,
];

// eps=0.06 0.8340509628407388
const GRAPH8_6: [u64; 100] = [
    31965120, 16540167, 14917112, 2097151, 8287009, 2131019, 0, 4160436, 268435455, 6393054, 15054783, 2167359, 33148158,
    2571136, 515820, 6480388, 66059500, 2131967, 14917119, 15060843, 63, 16547839, 2131093, 14937968, 255567, 16350, 15060191,
    507851, 2300340, 15592966, 33150580, 6402816, 6466355, 134201310, 6717406, 31965183, 6706529, 237055, 6403925, 16641759,
    15531193, 104052, 2146292, 66059487, 2167296, 7237927, 6420340, 1023, 6807033, 6731595, 6701025, 7239604, 66568140, 32238814,
    6402879, 2579104, 15054720, 104011, 3873, 6395255, 8322046, 33148159, 6462456, 101599, 3145211, 6393632, 31965127, 15062688,
    6739308, 33283576, 2161663, 2132126, 33159084, 7915, 2338635, 2131892, 237048, 15060769, 236, 515807, 14921452, 2319087,
    14937975, 2131385, 2192160, 14917337, 2179039, 15070014, 2167288, 15728120, 6483676, 8320885, 6393855, 6419454, 2322140,
    2198888, 8287231, 15187934, 2579956, 15530099,
];

// eps=0.02 0.94126
const GRAPH7_2: [u64; 100] = [
    255567, 2097151, 33867, 32767, 237048, 515806, 104096, 101599, 0, 64436, 63, 7916, 33942, 104063, 507851, 127777, 237055,
    7672, 127999, 3294, 241524, 104083, 34299, 7903, 39856, 3873, 101612, 515820, 241483, 131070, 1191, 106206, 111559, 35326,
    33952, 104011, 16350, 40683, 255574, 112468, 236, 102399, 33868, 128885, 1023, 33911, 114655, 127806, 102206, 235, 34300,
    515819, 112524, 101736, 223, 128875, 7679, 112575, 3440, 1048059, 1109, 101743, 111582, 102176, 101750, 104021, 3903, 507852,
    507903, 103864, 104444, 102183, 3447, 106359, 515583, 7, 104443, 33983, 35702, 106221, 104103, 3309, 101611, 4094, 104126,
    258041, 7915, 30, 35629, 515807, 128876, 104012, 105982, 114667, 3306, 36788, 101598, 35321, 114656, 39657,
];

// eps=0.04 0.82640
const GRAPH7_4: [u64; 100] = [
    33867, 3873, 7672, 255567, 507851, 0, 101598, 64436, 32767, 2097151, 63, 237055, 104052, 515820, 7915, 101736, 3295, 127777,
    237048, 236, 241535, 34299, 128884, 33877, 16350, 104011, 102398, 515807, 1023, 104083, 48063, 39348, 104096, 241492, 103871,
    111582, 1184, 128875, 34300, 131070, 507852, 104157, 515806, 235, 102207, 101599, 7916, 114655, 255574, 35131, 33868, 102176,
    241483, 106206, 48020, 515819, 30, 33919, 515583, 49140, 101610, 3440, 111559, 7, 7903, 112468, 3294, 258041, 101743,
    1048059, 39584, 111597, 255655, 35839, 3447, 507903, 33959, 40683, 104063, 33942, 255999, 101745, 127806, 104443, 106221,
    34743, 35702, 3309, 104103, 40445, 128885, 104126, 39645, 39419, 102182, 40881, 3577, 237049, 101750, 241613,
];

// eps=0.01 0.98033
const GRAPH6_1: [u64; 37] = [
    236, 1099, 1023, 7915, 1972, 3873, 3294, 32767, 0, 7672, 1191, 3447, 7903, 1184, 16350, 3440, 7916, 223, 1151, 1109, 7, 3903,
    7679, 4094, 1100, 1214, 3309, 235, 1531, 1532, 3306, 63, 3295, 222, 1456, 12, 7902,
];

fn get_repr(eps: f64, M: usize, N: usize) -> Vec<u64> {
    match ((eps * 100.0).round() as i32, N) {
        (_, 9) => GRAPH9_8.iter(),
        (_, 8) => GRAPH8_6.iter(),
        (1, 7) => GRAPH7_2.iter(),
        (_, 7) => GRAPH7_4.iter(),
        (_, 6) => GRAPH6_1.iter(),
        _ => unimplemented!(),
    }
    .take(M)
    .cloned()
    .collect()
}

提出情報

提出日時
問題 A - Graphorean
ユーザ wata_admin
言語 Rust (1.42.0)
得点 2296693238
コード長 50524 Byte
結果 AC
実行時間 4963 ms
メモリ 212188 KiB

ジャッジ結果

セット名 test_ALL
得点 / 配点 2296693238 / 50000000000
結果
AC × 50
セット名 テストケース
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_0000.txt AC 4963 ms 4064 KiB
test_0001.txt AC 4954 ms 3380 KiB
test_0002.txt AC 4953 ms 3496 KiB
test_0003.txt AC 4955 ms 3260 KiB
test_0004.txt AC 2075 ms 212188 KiB
test_0005.txt AC 4954 ms 3224 KiB
test_0006.txt AC 35 ms 4652 KiB
test_0007.txt AC 4954 ms 3612 KiB
test_0008.txt AC 4953 ms 3208 KiB
test_0009.txt AC 4954 ms 3720 KiB
test_0010.txt AC 4954 ms 3332 KiB
test_0011.txt AC 4954 ms 3500 KiB
test_0012.txt AC 4954 ms 3456 KiB
test_0013.txt AC 4954 ms 3228 KiB
test_0014.txt AC 4954 ms 3292 KiB
test_0015.txt AC 4954 ms 3512 KiB
test_0016.txt AC 4956 ms 3444 KiB
test_0017.txt AC 4954 ms 3420 KiB
test_0018.txt AC 1069 ms 112920 KiB
test_0019.txt AC 4954 ms 4576 KiB
test_0020.txt AC 4955 ms 3464 KiB
test_0021.txt AC 4955 ms 3332 KiB
test_0022.txt AC 4953 ms 3644 KiB
test_0023.txt AC 4955 ms 3252 KiB
test_0024.txt AC 4955 ms 4184 KiB
test_0025.txt AC 353 ms 41996 KiB
test_0026.txt AC 4954 ms 3416 KiB
test_0027.txt AC 41 ms 4868 KiB
test_0028.txt AC 4953 ms 3376 KiB
test_0029.txt AC 4954 ms 3680 KiB
test_0030.txt AC 159 ms 18484 KiB
test_0031.txt AC 4956 ms 3220 KiB
test_0032.txt AC 4955 ms 3368 KiB
test_0033.txt AC 4955 ms 3424 KiB
test_0034.txt AC 4955 ms 3268 KiB
test_0035.txt AC 4954 ms 3404 KiB
test_0036.txt AC 4954 ms 3388 KiB
test_0037.txt AC 409 ms 47676 KiB
test_0038.txt AC 1209 ms 127100 KiB
test_0039.txt AC 25 ms 3492 KiB
test_0040.txt AC 8 ms 2780 KiB
test_0041.txt AC 4953 ms 3436 KiB
test_0042.txt AC 4954 ms 3824 KiB
test_0043.txt AC 4954 ms 4124 KiB
test_0044.txt AC 65 ms 8484 KiB
test_0045.txt AC 4954 ms 3320 KiB
test_0046.txt AC 4954 ms 3408 KiB
test_0047.txt AC 4956 ms 3816 KiB
test_0048.txt AC 4954 ms 3188 KiB
test_0049.txt AC 4954 ms 3512 KiB