QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#640932 | #9458. Triangulation | sansen | AC ✓ | 55ms | 56768kb | Rust | 8.5kb | 2024-10-14 17:02:18 | 2024-10-14 17:02:21 |
Judging History
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