Submission #73939111


Source Code Expand

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

#[derive(Clone)]
struct Point {
    x: f64,
    y: f64,
    id: usize,
}

// 2 カラムゲームの値を計算
fn f1(u: &[f64], v: &[f64]) -> f64 {
    let n = u.len();
    if n == 0 {
        return 0.0;
    }
    
    // 純粋戦略の下限
    let mut r: f64 = 0.0;
    for i in 0..n {
        r = r.max(u[i].min(v[i]));
    }
    
    // u[i] > v[i] と u[i] < v[i] に分割
    let mut pos = Vec::new();
    let mut neg = Vec::new();
    
    for i in 0..n {
        let d = u[i] - v[i];
        if d > 1e-15 {
            pos.push(Point { x: d, y: u[i], id: i });
        } else if d < -1e-15 {
            neg.push(Point { x: -d, y: u[i], id: i });
        }
    }
    
    if pos.is_empty() || neg.is_empty() {
        return r;
    }
    
    // 凸包を構築
    let hull = |mut points: Vec<Point>| -> Vec<Point> {
        points.sort_by(|a, b| {
            a.x.partial_cmp(&b.x).unwrap()
                .then_with(|| b.y.partial_cmp(&a.y).unwrap())
        });
        let mut h: Vec<Point> = Vec::new();
        for t in points {
            while h.len() >= 2 {
                let b: &Point = &h[h.len() - 2];
                let c: &Point = &h[h.len() - 1];
                if (c.x - b.x) * (t.y - b.y) - (c.y - b.y) * (t.x - b.x) >= 0.0 {
                    h.pop();
                } else {
                    break;
                }
            }
            h.push(t);
        }
        h
    };
    
    let h1 = hull(pos);
    let h2 = hull(neg);
    
    // 凸包の交点から最適値を計算
    for p in &h1 {
        for q in &h2 {
            let z = (q.x * p.y + p.x * q.y) / (p.x + q.x);
            r = r.max(z);
        }
    }
    
    r
}

// 特定の行 s を除いた 2 カラムゲーム
fn f2(u: &[f64], v: &[f64], s: usize) -> f64 {
    let n = u.len();
    let mut a = Vec::with_capacity(n - 1);
    let mut b = Vec::with_capacity(n - 1);
    for i in 0..n {
        if i != s {
            a.push(u[i]);
            b.push(v[i]);
        }
    }
    f1(&a, &b)
}

// 行列のゲーム値を計算(列数が 1, 2, 3 の場合)
fn f3(g: &[Vec<f64>]) -> f64 {
    let r = g.len();
    if r == 0 {
        return 0.0;
    }
    let c = g[0].len();
    
    if c == 1 {
        let mut m: f64 = 1e18;
        for i in 0..r {
            m = m.min(g[i][0]);
        }
        return m;
    }
    
    if c == 2 {
        let mut ln = Vec::new();
        for i in 0..r {
            ln.push((g[i][0] - g[i][1], g[i][1]));
        }
        
        let mut cand = vec![0.0_f64, 1.0_f64];
        for i in 0..r {
            for j in (i + 1)..r {
                let d = ln[i].0 - ln[j].0;
                if d.abs() > 1e-15 {
                    let p = -(ln[i].1 - ln[j].1) / d;
                    if p >= -1e-9 && p <= 1.0 + 1e-9 {
                        cand.push(p.max(0.0).min(1.0));
                    }
                }
            }
        }
        
        let mut ans: f64 = -1e18;
        for &p in &cand {
            let mut m: f64 = 1e18;
            for i in 0..r {
                m = m.min(ln[i].0 * p + ln[i].1);
            }
            ans = ans.max(m);
        }
        return ans;
    }
    
    // c == 3
    let mut best: f64 = -1e18;
    let n = r;
    
    let mut a = vec![0.0_f64; n];
    let mut b = vec![0.0_f64; n];
    let mut c_vals = vec![0.0_f64; n];
    
    for i in 0..n {
        a[i] = g[i][0] - g[i][2];
        b[i] = g[i][1] - g[i][2];
        c_vals[i] = g[i][2];
    }
    
    let mut chk = |x: f64, y: f64| {
        if x < -1e-9 || y < -1e-9 || x + y > 1.0 + 1e-9 {
            return;
        }
        let x = x.max(0.0).min(1.0);
        let y = y.max(0.0).min(1.0 - x);
        
        let mut m: f64 = 1e18;
        for i in 0..n {
            m = m.min(a[i] * x + b[i] * y + c_vals[i]);
        }
        best = best.max(m);
    };
    
    // 3 行の交点
    for i in 0..n {
        for j in (i + 1)..n {
            for k in (j + 1)..n {
                let a1 = a[i] - a[j];
                let b1 = b[i] - b[j];
                let c1 = c_vals[j] - c_vals[i];
                let a2 = a[i] - a[k];
                let b2 = b[i] - b[k];
                let c2 = c_vals[k] - c_vals[i];
                
                let d = a1 * b2 - a2 * b1;
                if d.abs() < 1e-15 {
                    continue;
                }
                
                let x = (c1 * b2 - c2 * b1) / d;
                let y = (a1 * c2 - a2 * c1) / d;
                chk(x, y);
            }
        }
    }
    
    // 2 行の交点(境界)
    for i in 0..n {
        for j in (i + 1)..n {
            let d = b[i] - b[j];
            let e = c_vals[j] - c_vals[i];
            if d.abs() > 1e-15 {
                chk(0.0, e / d);
            }
        }
    }
    
    for i in 0..n {
        for j in (i + 1)..n {
            let d = a[i] - a[j];
            let e = c_vals[j] - c_vals[i];
            if d.abs() > 1e-15 {
                chk(e / d, 0.0);
            }
        }
    }
    
    // x + y = 1 の境界
    for i in 0..n {
        for j in (i + 1)..n {
            let d = (a[i] - b[i]) - (a[j] - b[j]);
            let e = (b[j] + c_vals[j]) - (b[i] + c_vals[i]);
            if d.abs() > 1e-15 {
                let x = e / d;
                chk(x, 1.0 - x);
            }
        }
    }
    
    // 頂点
    chk(0.0, 0.0);
    chk(1.0, 0.0);
    chk(0.0, 1.0);
    
    best
}

fn solve() {
    input! {
        n: usize,
    }
    
    let mut p = vec![[0.0_f64; 3]; n];
    for i in 0..n {
        input! {
            x0: i64, x1: i64, x2: i64
        }
        p[i] = [
            x0 as f64 / 1_000_000.0,
            x1 as f64 / 1_000_000.0,
            x2 as f64 / 1_000_000.0,
        ];
    }
    
    let col = [[1, 2], [0, 2], [0, 1]];
    
    let mut vs = [0.0_f64; 3];
    let mut id1 = [0usize; 3];
    let mut id2 = [0usize; 3];
    let mut rm1 = [0.0_f64; 3];
    let mut rm2 = [0.0_f64; 3];
    
    for b in 0..3 {
        let c0 = col[b][0];
        let c1 = col[b][1];
        
        let mut a = vec![0.0_f64; n];
        let mut bb = vec![0.0_f64; n];
        for i in 0..n {
            a[i] = p[i][c0];
            bb[i] = p[i][c1];
        }
        
        vs[b] = f1(&a, &bb);
        
        // 最適な行を特定
        let mut best: f64 = 0.0;
        let mut id = 0;
        for i in 0..n {
            let val = a[i].min(bb[i]);
            if val > best {
                best = val;
                id = i;
            }
        }
        
        let mut pos = Vec::new();
        let mut neg = Vec::new();
        for i in 0..n {
            let d = a[i] - bb[i];
            if d > 1e-15 {
                pos.push(Point { x: d, y: a[i], id: i });
            } else if d < -1e-15 {
                neg.push(Point { x: -d, y: a[i], id: i });
            }
        }
        
        let mut mi: isize = -1;
        let mut mj: isize = -1;
        let mut mv: f64 = best;
        
        if !pos.is_empty() && !neg.is_empty() {
            let hull = |mut points: Vec<Point>| -> Vec<Point> {
                points.sort_by(|a, b| {
                    a.x.partial_cmp(&b.x).unwrap()
                        .then_with(|| b.y.partial_cmp(&a.y).unwrap())
                });
                let mut h: Vec<Point> = Vec::new();
                for t in points {
                    while h.len() >= 2 {
                        let q: &Point = &h[h.len() - 2];
                        let r: &Point = &h[h.len() - 1];
                        if (r.x - q.x) * (t.y - q.y) - (r.y - q.y) * (t.x - q.x) >= 0.0 {
                            h.pop();
                        } else {
                            break;
                        }
                    }
                    h.push(t);
                }
                h
            };
            
            let h1 = hull(pos);
            let h2 = hull(neg);
            
            for pp in &h1 {
                for qq in &h2 {
                    let v = (qq.x * pp.y + pp.x * qq.y) / (pp.x + qq.x);
                    if v > mv + 1e-12 {
                        mv = v;
                        mi = pp.id as isize;
                        mj = qq.id as isize;
                    }
                }
            }
        }
        
        vs[b] = mv;
        
        if mi >= 0 {
            id1[b] = mi as usize;
            id2[b] = mj as usize;
        } else {
            id1[b] = id;
            id2[b] = id;
        }
        
        rm1[b] = f2(&a, &bb, id1[b]);
        
        if id1[b] != id2[b] {
            rm2[b] = f2(&a, &bb, id2[b]);
        } else {
            rm2[b] = rm1[b];
        }
    }
    
    // 候補行の集合
    let mut s: HashSet<usize> = HashSet::new();
    for b in 0..3 {
        s.insert(id1[b]);
        s.insert(id2[b]);
    }
    
    // 行列を構築
    let mut mat = Vec::new();
    
    {
        let mut r = vec![0.0_f64; 3];
        for b in 0..3 {
            r[b] = vs[b];
        }
        mat.push(r);
    }
    
    for &x in &s {
        let mut r = vec![0.0_f64; 3];
        for b in 0..3 {
            if x == id1[b] {
                r[b] = rm1[b];
            } else if x == id2[b] {
                r[b] = rm2[b];
            } else {
                r[b] = vs[b];
            }
        }
        mat.push(r);
    }
    
    let ans = f3(&mat);
    println!("{}", ans);
}

fn main() {
    input! {
        t: usize,
    }
    for _ in 0..t {
        solve();
    }
}

Submission Info

Submission Time
Task G - Conquest
User memoka
Language Rust (rustc 1.89.0)
Score 675
Code Size 9937 Byte
Status AC
Exec Time 82 ms
Memory 8016 KiB

Judge Result

Set Name Sample All
Score / Max Score 0 / 0 675 / 675
Status
AC × 3
AC × 77
Set Name Test Cases
Sample 00_sample_00.txt, 00_sample_01.txt, 00_sample_02.txt
All 00_sample_00.txt, 00_sample_01.txt, 00_sample_02.txt, 01_random_00.txt, 01_random_01.txt, 01_random_02.txt, 01_random_03.txt, 01_random_04.txt, 01_random_05.txt, 01_random_06.txt, 01_random_07.txt, 01_random_08.txt, 01_random_09.txt, 01_random_10.txt, 01_random_11.txt, 01_random_12.txt, 01_random_13.txt, 01_random_14.txt, 01_random_15.txt, 01_random_16.txt, 01_random_17.txt, 01_random_18.txt, 01_random_19.txt, 01_random_20.txt, 01_random_21.txt, 01_random_22.txt, 01_random_23.txt, 01_random_24.txt, 01_random_25.txt, 01_random_26.txt, 01_random_27.txt, 01_random_28.txt, 01_random_29.txt, 01_random_30.txt, 01_random_31.txt, 01_random_32.txt, 01_random_33.txt, 01_random_34.txt, 01_random_35.txt, 01_random_36.txt, 01_random_37.txt, 01_random_38.txt, 01_random_39.txt, 01_random_40.txt, 01_random_41.txt, 02_corner_1_00.txt, 02_corner_1_01.txt, 02_corner_1_02.txt, 02_corner_1_03.txt, 02_corner_1_04.txt, 02_corner_1_05.txt, 02_corner_1_06.txt, 02_corner_1_07.txt, 03_corner_2_00.txt, 03_corner_2_01.txt, 03_corner_2_02.txt, 03_corner_2_03.txt, 03_corner_2_04.txt, 03_corner_2_05.txt, 03_corner_2_06.txt, 03_corner_2_07.txt, 04_corner_3_00.txt, 04_corner_3_01.txt, 04_corner_3_02.txt, 04_corner_3_03.txt, 04_corner_3_04.txt, 04_corner_3_05.txt, 04_corner_3_06.txt, 04_corner_3_07.txt, 05_corner_4_00.txt, 05_corner_4_01.txt, 05_corner_4_02.txt, 05_corner_4_03.txt, 05_corner_4_04.txt, 05_corner_4_05.txt, 05_corner_4_06.txt, 05_corner_4_07.txt
Case Name Status Exec Time Memory
00_sample_00.txt AC 1 ms 2116 KiB
00_sample_01.txt AC 1 ms 2024 KiB
00_sample_02.txt AC 1 ms 2200 KiB
01_random_00.txt AC 4 ms 2200 KiB
01_random_01.txt AC 4 ms 2048 KiB
01_random_02.txt AC 4 ms 2200 KiB
01_random_03.txt AC 3 ms 2128 KiB
01_random_04.txt AC 4 ms 2104 KiB
01_random_05.txt AC 4 ms 2104 KiB
01_random_06.txt AC 4 ms 2116 KiB
01_random_07.txt AC 4 ms 2072 KiB
01_random_08.txt AC 4 ms 2020 KiB
01_random_09.txt AC 4 ms 2200 KiB
01_random_10.txt AC 3 ms 1996 KiB
01_random_11.txt AC 4 ms 2164 KiB
01_random_12.txt AC 4 ms 2020 KiB
01_random_13.txt AC 4 ms 2020 KiB
01_random_14.txt AC 4 ms 2192 KiB
01_random_15.txt AC 4 ms 2116 KiB
01_random_16.txt AC 4 ms 2284 KiB
01_random_17.txt AC 3 ms 2132 KiB
01_random_18.txt AC 4 ms 2080 KiB
01_random_19.txt AC 4 ms 2116 KiB
01_random_20.txt AC 4 ms 2020 KiB
01_random_21.txt AC 24 ms 2328 KiB
01_random_22.txt AC 22 ms 2328 KiB
01_random_23.txt AC 23 ms 2244 KiB
01_random_24.txt AC 16 ms 2228 KiB
01_random_25.txt AC 22 ms 2232 KiB
01_random_26.txt AC 23 ms 2148 KiB
01_random_27.txt AC 24 ms 2244 KiB
01_random_28.txt AC 37 ms 2020 KiB
01_random_29.txt AC 34 ms 2264 KiB
01_random_30.txt AC 37 ms 2128 KiB
01_random_31.txt AC 25 ms 2284 KiB
01_random_32.txt AC 33 ms 2020 KiB
01_random_33.txt AC 38 ms 2048 KiB
01_random_34.txt AC 37 ms 2040 KiB
01_random_35.txt AC 38 ms 1996 KiB
01_random_36.txt AC 33 ms 1996 KiB
01_random_37.txt AC 37 ms 2128 KiB
01_random_38.txt AC 26 ms 2144 KiB
01_random_39.txt AC 33 ms 2132 KiB
01_random_40.txt AC 38 ms 2080 KiB
01_random_41.txt AC 37 ms 1996 KiB
02_corner_1_00.txt AC 81 ms 7044 KiB
02_corner_1_01.txt AC 82 ms 7552 KiB
02_corner_1_02.txt AC 82 ms 7188 KiB
02_corner_1_03.txt AC 81 ms 7148 KiB
02_corner_1_04.txt AC 60 ms 2700 KiB
02_corner_1_05.txt AC 60 ms 2820 KiB
02_corner_1_06.txt AC 60 ms 2712 KiB
02_corner_1_07.txt AC 60 ms 2760 KiB
03_corner_2_00.txt AC 64 ms 7700 KiB
03_corner_2_01.txt AC 62 ms 7224 KiB
03_corner_2_02.txt AC 28 ms 7236 KiB
03_corner_2_03.txt AC 33 ms 7168 KiB
03_corner_2_04.txt AC 39 ms 2720 KiB
03_corner_2_05.txt AC 31 ms 2820 KiB
03_corner_2_06.txt AC 34 ms 2676 KiB
03_corner_2_07.txt AC 26 ms 2844 KiB
04_corner_3_00.txt AC 29 ms 7412 KiB
04_corner_3_01.txt AC 51 ms 7896 KiB
04_corner_3_02.txt AC 28 ms 7360 KiB
04_corner_3_03.txt AC 51 ms 8016 KiB
04_corner_3_04.txt AC 19 ms 2828 KiB
04_corner_3_05.txt AC 40 ms 2800 KiB
04_corner_3_06.txt AC 18 ms 2856 KiB
04_corner_3_07.txt AC 40 ms 2576 KiB
05_corner_4_00.txt AC 38 ms 2260 KiB
05_corner_4_01.txt AC 35 ms 2420 KiB
05_corner_4_02.txt AC 40 ms 2372 KiB
05_corner_4_03.txt AC 38 ms 2416 KiB
05_corner_4_04.txt AC 38 ms 2308 KiB
05_corner_4_05.txt AC 39 ms 2280 KiB
05_corner_4_06.txt AC 39 ms 2364 KiB
05_corner_4_07.txt AC 37 ms 2308 KiB