QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#640932#9458. TriangulationsansenAC ✓55ms56768kbRust8.5kb2024-10-14 17:02:182024-10-14 17:02:21

Judging History

你现在查看的是最新测评结果

  • [2024-10-14 17:02:21]
  • 评测
  • 测评结果:AC
  • 用时:55ms
  • 内存:56768kb
  • [2024-10-14 17:02:18]
  • 提交

answer

fn rand_memory() -> usize {
    Box::into_raw(Box::new("I hope this is a random number")) as usize
}

fn rand() -> usize {
    static mut X: usize = 0;
    unsafe {
        if X == 0 {
            X = rand_memory();
        }
        X ^= X << 13;
        X ^= X >> 17;
        X ^= X << 5;
        X
    }
}

fn shuffle<T>(a: &mut [T]) {
    for i in 1..a.len() {
        let p = rand() % (i + 1);
        a.swap(i, p);
    }
}

// ---------- begin scannner ----------
#[allow(dead_code)]
mod scanner {
    use std::str::FromStr;
    pub struct Scanner<'a> {
        it: std::str::SplitWhitespace<'a>,
    }
    impl<'a> Scanner<'a> {
        pub fn new(s: &'a String) -> Scanner<'a> {
            Scanner {
                it: s.split_whitespace(),
            }
        }
        pub fn next<T: FromStr>(&mut self) -> T {
            self.it.next().unwrap().parse::<T>().ok().unwrap()
        }
        pub fn next_bytes(&mut self) -> Vec<u8> {
            self.it.next().unwrap().bytes().collect()
        }
        pub fn next_chars(&mut self) -> Vec<char> {
            self.it.next().unwrap().chars().collect()
        }
        pub fn next_vec<T: FromStr>(&mut self, len: usize) -> Vec<T> {
            (0..len).map(|_| self.next()).collect()
        }
    }
}
// ---------- end scannner ----------

use std::collections::*;
use std::io::Write;

type Map<K, V> = BTreeMap<K, V>;
type Set<T> = BTreeSet<T>;
type Deque<T> = VecDeque<T>;

fn main() {
    use std::io::Read;
    let mut s = String::new();
    std::io::stdin().read_to_string(&mut s).unwrap();
    let mut sc = scanner::Scanner::new(&s);
    let out = std::io::stdout();
    let mut out = std::io::BufWriter::new(out.lock());
    run(&mut sc, &mut out);
}

fn run<W: Write>(sc: &mut scanner::Scanner, out: &mut std::io::BufWriter<W>) {
    let t: u32 = sc.next();
    for _ in 0..t {
        let n: usize = sc.next();
        let mut p = vec![(0, 0); n];
        for p in p.iter_mut() {
            p.0 = sc.next::<i64>();
            p.1 = sc.next::<i64>();
        }
        let mut w = vec![vec![0; n]; n];
        for w in w.iter_mut().flatten() {
            *w = sc.next::<i32>();
        }
        /*
        let n = 18;
        let mut p = (0..n).map(|_| ((rand() % 1000001) as i64, (rand() % 1000001) as i64)).collect::<Vec<_>>();
        let mut w = vec![vec![1; n]; n];
        for i in 0..n {
            w[i][i] = 0;
        }
        */
        loop {
            let a = (rand() % 1001) as i64 - 500;
            let b = (rand() % 1001) as i64 - 500;
            let c = (rand() % 1001) as i64 - 500;
            let d = (rand() % 1001) as i64 - 500;
            if a * d - b * c == 0 {
                continue;
            }
            let q = p.iter().map(|p| (a * p.0 + b * p.1, c * p.0 + d * p.1)).collect::<Vec<_>>();
            let mut x = Set::new();
            let mut y = Set::new();
            let mut ok = true;
            for q in q.iter() {
                ok &= x.insert(q.0);
                ok &= y.insert(q.1);
            }
            if ok {
                p = q;
                break;
            }
        }
        let (cost, way) = solve(p, w);
        writeln!(out, "{} {}", cost, way).ok();
    }
}

// https://x.com/maspy_stars/status/1845392020644430009
//
// 上のものと全く同一だけどメモ
// 最適化はmonotone path への点追加、削除でOK
//
// 数え上げは何かしら固定しないといけない
//
// 適当な三角形分割を一意に生成するには?
// monotone path への点の挿入/削除をする際
// 操作可能な最も小さい点番号への操作を行う
// という具合で出来はする
// ただこれだと添字の順序が非自明な順番になってて困る
// 必ず三角形を一つ追加していくのでBFSぽくやれば大丈夫か

// x, y が全て異なると仮定したコード
fn solve(p: Vec<(i64, i64)>, w: Vec<Vec<i32>>) -> (i32, u64) {
    // (x, y) の辞書順でソート
    // コストの表を作り直す
    let n = p.len();
    let mut ord = (0..n).collect::<Vec<_>>();
    ord.sort_by_key(|&x| p[x]);
    let mut cost = [[0; 18]; 18];
    for i in 0..n {
        for j in 0..n {
            cost[i][j] = w[ord[i]][ord[j]];
        }
    }
    let w = cost;
    let p = (0..n).map(|i| p[ord[i]]).collect::<Vec<_>>();
    let sign = |a: (i64, i64), b: (i64, i64), c: (i64, i64)| -> i64 {
        ((c.1 - a.1) * (b.0 - a.0) - (c.0 - a.0) * (b.1 - a.1)).signum()
    };
    // 初期状態の下側凸包の計算
    let mut lower = vec![];
    for i in 0..n {
        let c = p[i];
        while lower.len() >= 2 {
            let len = lower.len();
            let b = p[lower[len - 1]];
            let a = p[lower[len - 2]];
            if sign(a, b, c) <= 0 {
                lower.pop();
            } else {
                break;
            }
        }
        lower.push(i);
    }
    let base = lower.windows(2).map(|a| w[a[0]][a[1]]).sum::<i32>();
    let lower = lower.iter().fold(0, |s, a| s | (1 << *a));
    // 辺ab と点cを結ぶことができる時のコスト
    // 内部に点がない時かつcがabの範囲内である時のみ結べる
    // コストは上下で決まる
    let mut cost = [[[-1; 18]; 18]; 18];
    let mut cond = [[[2; 18]; 18]; 18];
    for (b, &pb) in p.iter().enumerate() {
        for (c, &pc) in p.iter().enumerate().take(b) {
            for (a, &pa) in p.iter().enumerate().take(c) {
                let q = sign(pa, pc, pb);
                if ((a + 1)..b).all(|x| {
                    x == c || {
                        let p = p[x];
                        let d = sign(pa, p, pb);
                        let e = sign(pa, p, pc);
                        let f = sign(pc, p, pb);
                        if q <= 0 {
                            d > 0 || (e < 0 || f < 0)
                        } else {
                            d < 0 || (e > 0 || f > 0)
                        }
                    }
                }) {
                    if q <= 0 {
                        cost[a][c][b] = w[a][c] + w[c][b];
                        cond[a][c][b] = 0;
                    } else {
                        cost[a][c][b] = w[a][b];
                        cond[a][c][b] = 1;
                    }
                }
            }
        }
    }
    let inf = std::i32::MAX / 2;
    let mut sum = vec![vec![inf; 1 << n]; n];
    let mut way = vec![vec![0; 1 << n]; n];
    let mut pos = vec![(0, lower)];
    sum[0][lower] = base;
    way[0][lower] = 1;
    let mut memo = vec![];
    let mut next_pos = vec![];
    loop {
        let mut update = false;
        memo.clear();
        for &(k, x) in pos.iter() {
            memo.push((sum[k][x], way[k][x]));
            sum[k][x] = inf;
            way[k][x] = 0;
        }
        next_pos.clear();
        let mut upd = |k: usize, x: usize, cost: i32, w: u64| {
            update = true;
            let po = &mut sum[k][x];
            if *po == inf {
                next_pos.push((k, x));
            }
            if *po > cost {
                *po = cost;
                way[k][x] = w;
            } else if *po == cost {
                way[k][x] += w;
            }
        };
        for (&(k, x), &(sum, way)) in pos.iter().zip(memo.iter()) {
            for i in k..n {
                if let (Some(a), Some(b)) = (prev_bit(x, i), next_bit(x, i)) {
                    if x >> i & 1 == cond[a][i][b] {
                        let c = cost[a][i][b];
                        upd(a, x ^ (1 << i), sum + c, way);
                    }
                }
            }
        }
        if !update {
            break;
        }
        std::mem::swap(&mut pos, &mut next_pos);
    }
    let v = memo.iter().map(|p| p.0).min().unwrap();
    (v, memo.iter().filter(|p| p.0 == v).map(|p| p.1).sum::<u64>())
}

// 以下の処理はx < 60 を仮定している

// x < y, bit >> y & 1 == 1 なものを返す
fn next_bit(bit: usize, x: usize) -> Option<usize> {
    if bit >> (x + 1) == 0 {
        None
    } else {
        let k = (bit >> (x + 1)).trailing_zeros();
        Some(x + k as usize + 1)
    }
}

// x > y, bit >> y & 1 == 1 なものを返す
fn prev_bit(bit: usize, x: usize) -> Option<usize> {
    if x == 0 || bit << (64 - x) == 0 {
        None
    } else {
        let k = (bit << (64 - x)).leading_zeros();
        Some(x - 1 - k as usize)
    }
}

这程序好像有点Bug,我给组数据试试?

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 0ms
memory: 2268kb

input:

2
4
0 0
1 1
1 0
0 1
0 1 1 1
1 0 1 1
1 1 0 1
1 1 1 0
4
0 0
3 0
1 3
1 1
0 1 1 1
1 0 1 1
1 1 0 1
1 1 1 0

output:

5 2
6 1

result:

ok 2 lines

Test #2:

score: 0
Accepted
time: 55ms
memory: 56768kb

input:

68
3
454 364
117 336
271 84
0 6 2
6 0 10
2 10 0
4
454 364
117 336
271 84
274 296
0 3 2 10
3 0 6 4
2 6 0 5
10 4 5 0
4
603 817
230 695
230 303
604 183
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
5
454 364
117 336
271 84
274 296
220 225
0 1 7 3 2
1 0 4 4 2
7 4 0 1 5
3 4 1 0 0
2 2 5 0 0
5
666667 788675
333173 78858...

output:

18 1
30 1
0 2
27 1
38 2
35 5
54 1
44 2
18 14
69 1
12 1
88 42
59 1
23 8
180 150
80 1
23 2
0 780
30 12
504 4550
30 4
19656 26888
29 6
26700 168942
24 88
22770 1098904
21 28
30816 7281984
24 27
15327 49789428
24 4
16338 342305320
21 48
42615 2410168190
22 360
44928 17309628327
1240448 1
2613579 1
19532...

result:

ok 68 lines

Extra Test:

score: 0
Extra Test Passed