E - Transitivity Editorial by ngtkana


公式解説よりも漸近的に遅い解法ですが、実行時間には余裕で間に合うため、ご紹介です。

Floyd–Warshall のアルゴリズムにより推移閉包を計算すると \(O ( N ^ 3 )\) 時間で計算できますが、これを bitset (AtCoder では FixedBitSet というクレートが使えます。)で高速化すると、\(O ( N ^ 3 / w )\) 時間(\(w\) はワードサイズ)となります。

Rust 78 ms

use fixedbitset::FixedBitSet;
use proconio::{input, marker::Usize1};

fn main() {
    input! {
        n: usize,
        m: usize,
        edges: [(Usize1, Usize1); m],
    }
    let mut trans = vec![FixedBitSet::with_capacity(n); n];
    (0..n).for_each(|i| trans[i].insert(i));
    for &(i, j) in &edges {
        trans[i].insert(j);
    }
    for j in 0..n {
        for i in 0..n {
            if trans[i][j] {
                let x = trans[j].clone();
                trans[i] |= x;
            }
        }
    }
    let ans = trans.iter().map(|row| row.count_ones(..)).sum::<usize>() - m - n;
    println!("{}", ans);
}

posted:
last update: