Google Code Jam 2019 Round 1B - Fair Fight

問題

codingcompetitions.withgoogle.com

数列 \{c_i\} \{d_i\} が与えられる。 | max(c_l, c_{l+1}, ... , c_r) - max(d_l, d_{l+1} , ... , d_r)| \leq k  となるような (l, r) の組の数を求めよ。

解法

 | max(c_l, c_{l+1}, ... , c_r) - max(d_l, d_{l+1} , ... , d_r)| \gt k  となるような (l, r) の組の数を求めて全体から引くことにする。
 max(c_l, c_{l+1}, ... , c_r) - max(d_l, d_{l+1} , ... , d_r) \gt k    max(c_l, c_{l+1}, ... , c_r) - max(d_l, d_{l+1} , ... , d_r) \gt k  は c と d を入れ替えることで独立に同じように求めることができる。

各 i について c_i が最大となるような c の区間を求める。これは Sparse Table で二分探索を二回やると求まる。次に、この区間内で  max(d_l, d_{l+1}, ... , d_i) < c_i -k となるような l と  max(d_i, d_{i+1}, ... , d_r) < c_i -k となるような r を求める。

コード

use self::sparse_table::SparseTable;
use std::cmp;

fn main() {
    let s = std::io::stdin();
    let mut sc = Scanner { stdin: s.lock() };
    let t: usize = sc.read();
    for t in 0..t {
        let n: usize = sc.read();
        let k: i64 = sc.read();
        let c: Vec<i64> = sc.vec(n);
        let d: Vec<i64> = sc.vec(n);
        let ans = n * (n + 1) / 2 - solve(&c, &d, k) - solve(&d, &c, k);
        println!("Case #{}: {}", t + 1, ans);
    }
}

fn solve(c: &[i64], d: &[i64], k: i64) -> usize {
    let n = c.len();
    let c_st = SparseTable::from(c, 0, cmp::max);
    let d_st = SparseTable::from(d, 0, cmp::max);
    (0..n)
        .filter(|&i| d[i] < c[i] - k)
        .map(|i| {
            let mut ng = n + 1;
            let mut ok = i + 1;
            while ng - ok > 1 {
                let m = (ok + ng) >> 1;
                if c_st.get(i, m) <= c[i] {
                    ok = m;
                } else {
                    ng = m;
                }
            }
            let right = ok;

            let mut ok = i as i64;
            let mut ng = -1;
            while ok - ng > 1 {
                let m = (ok + ng) >> 1;
                if c_st.get(m as usize, i) < c[i] {
                    ok = m;
                } else {
                    ng = m;
                }
            }
            let left = ok;

            let mut ok = i + 1;
            let mut ng = right + 1;
            while ng - ok > 1 {
                let m = (ok + ng) >> 1;
                if d_st.get(i, m) < c[i] - k {
                    ok = m;
                } else {
                    ng = m;
                }
            }
            let right = ok;

            let mut ok = i as i64;
            let mut ng = left - 1;
            while ok - ng > 1 {
                let m = (ok + ng) >> 1;
                if d_st.get(m as usize, i + 1) < c[i] - k {
                    ok = m;
                } else {
                    ng = m;
                }
            }
            let left = ok as usize;
            (i - left + 1) * (right - i)
        })
        .sum()
}

pub mod sparse_table {
    use std::cmp;

    pub struct SparseTable<T, F> {
        data: Vec<Vec<T>>,
        op: F,
    }

    impl<T, F> SparseTable<T, F>
    where
        T: Copy,
        F: Fn(T, T) -> T,
    {
        pub fn from(v: &[T], init: T, op: F) -> Self {
            let size = v.len().next_power_of_two();
            let count = size.trailing_zeros() as usize + 1;
            let mut data = vec![vec![init; size]; count];
            for (i, v) in v.iter().cloned().enumerate() {
                data[0][i] = v;
            }
            for c in 1..count {
                for i in 0..size {
                    let next = cmp::min(size - 1, i + (1 << (c - 1)));
                    data[c][i] = op(data[c - 1][i], data[c - 1][next]);
                }
            }

            Self { data: data, op: op }
        }

        /// get the result for [l, r)
        pub fn get(&self, l: usize, r: usize) -> T {
            assert!(l < r, "l={} r={}", l, r);
            let length = r - l;
            if length == 1 {
                return self.data[0][l];
            }
            let block_size = length.next_power_of_two() >> 1;
            let c = block_size.trailing_zeros() as usize;
            let left = self.data[c][l];
            let right = self.data[c][r - block_size];
            (self.op)(left, right)
        }
    }
}

pub struct Scanner<R> {
    stdin: R,
}

impl<R: std::io::Read> Scanner<R> {
    pub fn read<T: std::str::FromStr>(&mut self) -> T {
        use std::io::Read;
        let buf = self
            .stdin
            .by_ref()
            .bytes()
            .map(|b| b.unwrap())
            .skip_while(|&b| b == b' ' || b == b'\n' || b == b'\r')
            .take_while(|&b| b != b' ' && b != b'\n' && b != b'\r')
            .collect::<Vec<_>>();
        unsafe { std::str::from_utf8_unchecked(&buf) }
            .parse()
            .ok()
            .expect("Parse error.")
    }
    pub fn vec<T: std::str::FromStr>(&mut self, n: usize) -> Vec<T> {
        (0..n).map(|_| self.read()).collect()
    }
    pub fn chars(&mut self) -> Vec<char> {
        self.read::<String>().chars().collect()
    }
}