以下の内容はhttps://inamori.hateblo.jp/entry/2025/09/06/122221より取得しました。


AtCoder Beginner Contest 421 E

https://atcoder.jp/contests/abc421/tasks/abc421_e

今のダイスの状態をキープしたダイスは面の数を負にした数で表します。また、ソートして状態数を減らします。マスクが32通りあるので、その中で最大値を選びます。逆から辿って解答を得ます。

// Yacht
#![allow(non_snake_case)]

use std::collections::{HashSet, HashMap};


//////////////////// library ////////////////////

fn read<T: std::str::FromStr>() -> T {
    let mut line = String::new();
    std::io::stdin().read_line(&mut line).ok();
    line.trim().parse().ok().unwrap()
}

fn read_vec<T: std::str::FromStr>() -> Vec<T> {
    read::<String>().split_whitespace()
            .map(|e| e.parse().ok().unwrap()).collect()
}


//////////////////// process ////////////////////

type State = (i32, i32, i32, i32, i32);
type Probs = HashMap<State, f64>;

fn state_to_array(s: &State) -> [i32; 5] {
    [s.0, s.1, s.2, s.3, s.4]
}

fn array_to_state(a: &[i32; 5]) -> State {
    (a[0], a[1], a[2], a[3], a[4])
}

fn product(n: usize, A: &Vec<i32>) -> Vec<Vec<i32>> {
    if n == 1 {
        A.iter().map(|&a| vec![a]).collect::<Vec<Vec<i32>>>()
    }
    else if n % 2 == 1 {
        let mut v: Vec<Vec<i32>> = vec![];
        let v1 = product(n-1, A);
        for &e1 in A {
            for e2 in v1.iter() {
                let e = [&[e1], e2.as_slice()].concat();
                v.push(e)
            }
        }
        v
    }
    else {
        let mut v: Vec<Vec<i32>> = vec![];
        let v1 = product(n/2, A);
        for e1 in v1.iter() {
            for e2 in v1.iter() {
                let e = [e1.as_slice(), e2.as_slice()].concat();
                v.push(e)
            }
        }
        v
    }
}

fn compute_probabilities(n: usize, A: &Vec<i32>) -> Probs {
    let mut probs: Probs = Probs::new();
    if n == 0 {
        probs.insert((0, 0, 0, 0, 0), 1.0);
        return probs
    }
    
    let vs = product(n, A);
    for v in &vs {
        let mut w: [i32; 5] = [0; 5];
        for i in 0..n {
            w[i+5-n] = v[i]
        }
        w.sort();
        let s = array_to_state(&w);
        let e = probs.entry(s).or_insert(0.0);
        (*e) += 1.0 / (vs.len() as f64)
    }
    probs
}

fn score(s: &State) -> i32 {
    let mut counter: HashMap<i32, i32> = HashMap::new();
    for X in [s.0, s.1, s.2, s.3, s.4] {
        let e = counter.entry(X.abs()).or_insert(0);
        (*e) += 1
    }
    counter.into_iter().map(|(X, n)| X * n).max().unwrap()
}

// (-3, -2, 0, 0, 3) + (0, 0, 0, 1, 5) -> (-3, -3, -2, 1, 5)
fn add(s1: &State, s2: &State) -> State {
    let mut v: [i32; 5] = [0; 5];
    let a1 = state_to_array(s1);
    let a2 = state_to_array(s2);
    let mut j: usize = 0;
    for i in 0..5 {
        if a1[i] != 0 {
            v[j] = -(a1[i].abs());
            j += 1
        }
        if a2[i] != 0 {
            v[j] = a2[i];
            j += 1
        }
    }
    v.sort();
    array_to_state(&v)
}

fn mask(s: &State, flags: usize) -> State {
    let mut a = state_to_array(s);
    for i in 0..5 {
        if ((flags >> i) & 1) == 1 {
            a[i] = 0
        }
    }
    a.sort();
    array_to_state(&a)
}

fn is_valid_mask(flags: usize, a: &[i32; 5]) -> bool {
    (0..5).all(|i| ((flags >> i) & 1) == 0 || a[i] > 0)
}

// 最も適切なマスクのときの期待値
fn max_exp_value(s: &State, pss: &Vec<Probs>,
                        E: &HashMap<State, f64>) -> f64 {
    let a = state_to_array(s);
    let mut e_max: f64 = 0.0;
    for flags in 0..32 {
        if !is_valid_mask(flags, &a) {
            continue
        }
        
        let n: usize = (0..5).map(|i| (flags >> i) & 1).sum::<usize>();
        let s1 = mask(s, flags);
        let mut e_each: f64 = 0.0;
        for (&s2, &prob) in pss[n].iter() {
            let s3 = add(&s1, &s2);
            if let Some(&e) = E.get(&s3) {
                e_each += prob * e
            }
        }
        if e_each > e_max {
            e_max = e_each
        }
    }
    e_max
}

fn collect_states(A: &Vec<i32>) -> Vec<State> {
    let mut B: Vec<i32> = A.clone();
    for &a in A {
        B.push(-a)
    }
    
    let vs = product(5, &B);
    let mut set: HashSet<State> = HashSet::new();
    for v in vs {
        let mut a: [i32; 5] = [v[0], v[1], v[2], v[3], v[4]];
        a.sort();
        set.insert(array_to_state(&a));
    }
    set.into_iter().collect::<Vec<_>>()
}

fn F(A: Vec<i32>) -> f64 {
    let mut E: [HashMap<State, f64>; 3] = [HashMap::new(),
                                            HashMap::new(),
                                            HashMap::new()];
    let pss: Vec<Probs> = (0..6).map(|n| compute_probabilities(n, &A)).
                                                                collect();
    let all_states = collect_states(&A);
    for state in all_states.iter() {
        E[0].insert(*state, score(state) as f64);
    }
    
    for state in all_states.iter() {
        E[1].insert(*state, max_exp_value(state, &pss, &E[0]));
    }
    
    for (state, _) in pss[5].iter() {
        E[2].insert(*state, max_exp_value(state, &pss, &E[1]));
    }
    
    pss[5].iter().map(|(&s, &p)| p * E[2].get(&s).unwrap()).sum::<f64>()
}

fn main() {
    let A: Vec<i32> = read_vec();
    println!("{}", F(A))
}



以上の内容はhttps://inamori.hateblo.jp/entry/2025/09/06/122221より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14