E - At Least One Editorial by cunitac


整数 \(s, t\ (1\le s \le t \le M)\) について、数列 \((s, \ldots, t)\) を区間 \([s,t]\) と呼ぶことにする。また、\(1\le s\le t\le M\) を満たさないとき、\([s,t]\) は空列を意味するものとする。

長さ \(k\) の良い数列でない区間を数えて、長さ \(k\) の区間の総数 \(M-k+1\) から引くことにする。

区間 \([s,t]\) が良い数列でないとき、すべての \(i\) について \([s,t]\)\([1, A_i-1], [A_i+1, B_i-1], [B_i+1, M]\) のいずれかの部分列である。よって、高々 \(3N\) 個の区間について、そのいずれかに含まれる区間の数を長さごとに求められればよい。

上で挙げた高々 \(3N\) 個の区間を \([C_1, D_1], \ldots, [C_K, D_K]\) と書く。\([C_i, D_i]\) のうち \(C_i = s\) であるようなものの長さの最大値を \(l_s\) とおけば、\(s\) から始まる区間であって良い数列でないものの長さの最大値 \(L_s\) は漸化式 \(L_s = \max\{l_s, L_{s-1} - 1\}\) を用いて求められる。

\(s\) から始まる区間であって長さ \(L_s\) 以下の数列はすべて良い数列でないから、長さ \(k\) の区間であって良い数列でないものの数は、\(L_s = k\) であるような \(s\) を数えた後に累積和を用いて求めることができる。

実装例 (Rust)

use proconio::{input, marker::Usize1};
fn main() {
    input!(n: usize, m: usize, ab: [(Usize1, Usize1); n]);
    let mut l = vec![0; m];
    for &(a, b) in &ab {
        if a > 0 {
            l[0] = l[0].max(a);
        }
        if a + 1 < b {
            l[a + 1] = l[a + 1].max(b - a - 1);
        }
        if b + 1 < m {
            l[b + 1] = l[b + 1].max(m - b - 1);
        }
    }
    // l を L にする
    for i in 1..m {
        l[i] = (l[i] + 1).max(l[i - 1]) - 1;
    }
    let mut g = vec![0; m];
    for &k in &l {
        if k > 0 {
            g[k - 1] += 1;
        }
    }
    for k in (1..m).rev() {
        g[k - 1] += g[k];
    }
    let f = g
        .iter()
        .enumerate()
        .map(|(i, &g)| m - i - g)
        .map(|f| f.to_string())
        .collect::<Vec<_>>()
        .join(" ");
    println!("{}", f);
}

posted:
last update: