AtCoder Regular Contest 059 E - キャンディーとN人の子供 / Children and Candies

解法

求める値は以下の式で表される。

{ \displaystyle
ans = \sum_{c_1+c_2+c_3+...+c_N=C} \sum_{x_1=A_1}^{B_1} \sum_{x_2=A_2}^{B_2} ... \sum_{x_N=A_N}^{B_N} ( x_1^{c_1} + x_2^{c_2} + ... + x_N^{c_N} )
}

これは解説動画の変形を駆使して、以下のように変形できる。

{ \displaystyle
ans = \sum_{c_1+c_2+c_3+...+c_N=C} ( \sum_{x_1=A_1}^{B_1} x_1^{c_1} )  ( \sum_{x_2=A_2}^{B_2} x_2^{c_2} ) ... ( \sum_{x_N=A_N}^{B_N} x_N^{c_N} ) 
}

よって以下のような動的計画法で解ける。

{ \displaystyle
dp_{0, 0} = 1 \\
dp_{i+1, from+add} = dp_{i,from} \times \sum_{x_i=A_i}^{B_i}x_i^{add} \\
ans = dp_{N, C}
}

コード

use self::mod_int::ModInt;

const MOD: usize = 1e9 as usize + 7;

fn main() {
    let stdin = std::io::stdin();
    let mut sc = Scanner {
        reader: stdin.lock(),
    };

    let n: usize = sc.read();
    let c: usize = sc.read();
    let a: Vec<usize> = sc.read_vec(n);
    let b: Vec<usize> = sc.read_vec(n);

    let b_max: usize = *b.iter().max().unwrap();

    // pow[i][j] := i**j
    let mut pow = vec![vec![ModInt::new(0); c + 1]; b_max + 1];
    for i in 1..(b_max + 1) {
        pow[i][0] = ModInt::new(1);
        for j in 0..c {
            pow[i][j + 1] = pow[i][j] * i;
        }
    }

    // sum[i][c] := sum(pow[a[i]..b[i]+1][c])
    let mut sum = vec![vec![ModInt::new(0); c + 1]; n];
    for i in 0..n {
        let from = a[i];
        let to = b[i];
        for c in 0..(c + 1) {
            for t in from..(to + 1) {
                sum[i][c] += pow[t][c];
            }
        }
    }

    let mut dp = vec![ModInt::new(0); c + 1];
    dp[0] = ModInt::new(1);
    for i in 0..n {
        let mut next = vec![ModInt::new(0); c + 1];
        for from in 0..(c + 1) {
            for add in 0..(c + 1) {
                if from + add > c {
                    continue;
                }
                next[from + add] += dp[from] * sum[i][add];
            }
        }
        dp = next;
    }
    println!("{}", dp[c].value);
}

pub mod mod_int {
    use std::ops::{Add, AddAssign, Mul, MulAssign, Rem, Sub, SubAssign};

    #[derive(Copy)]
    pub struct ModInt<T> {
        pub value: T,
        modulo: T,
    }

    impl<T> Clone for ModInt<T>
    where
        T: Copy,
    {
        fn clone(&self) -> Self {
            ModInt {
                value: self.value,
                modulo: self.modulo,
            }
        }

        fn clone_from(&mut self, source: &ModInt<T>) {
            self.value = source.value;
            self.modulo = source.modulo;
        }
    }

    impl<T> Add<ModInt<T>> for ModInt<T>
    where
        T: Add<Output = T> + Sub<Output = T> + Copy + PartialOrd,
    {
        type Output = ModInt<T>;
        fn add(self, rhs: ModInt<T>) -> ModInt<T> {
            self + rhs.value
        }
    }

    impl<T> Add<T> for ModInt<T>
    where
        T: Add<Output = T> + Sub<Output = T> + Copy + PartialOrd,
    {
        type Output = ModInt<T>;
        fn add(self, rhs: T) -> ModInt<T> {
            let m = self.modulo;
            let mut t = rhs + self.value;
            if t >= m {
                t = t - m;
            }
            ModInt {
                value: t,
                modulo: self.modulo,
            }
        }
    }

    impl<T> Sub<T> for ModInt<T>
    where
        T: PartialOrd + Copy + Add<Output = T> + Sub<Output = T> + Rem<Output = T>,
    {
        type Output = ModInt<T>;
        fn sub(self, rhs: T) -> ModInt<T> {
            let rhs = if rhs >= self.modulo {
                rhs % self.modulo
            } else {
                rhs
            };
            let value = if self.value < rhs {
                self.value + self.modulo
            } else {
                self.value
            };
            ModInt {
                value: value - rhs,
                modulo: self.modulo,
            }
        }
    }

    impl<T> Sub<ModInt<T>> for ModInt<T>
    where
        T: PartialOrd + Copy + Add<Output = T> + Sub<Output = T> + Rem<Output = T>,
    {
        type Output = ModInt<T>;
        fn sub(self, rhs: ModInt<T>) -> ModInt<T> {
            self - rhs.value
        }
    }

    impl<T> AddAssign<T> for ModInt<T>
    where
        T: Add<Output = T> + Sub<Output = T> + Copy + PartialOrd,
    {
        fn add_assign(&mut self, other: T) {
            *self = *self + other;
        }
    }
    impl<T> AddAssign<ModInt<T>> for ModInt<T>
    where
        T: Add<Output = T> + Sub<Output = T> + Copy + PartialOrd,
    {
        fn add_assign(&mut self, other: ModInt<T>) {
            *self = *self + other;
        }
    }

    impl<T> SubAssign<T> for ModInt<T>
    where
        T: PartialOrd + Copy + Add<Output = T> + Sub<Output = T> + Rem<Output = T>,
    {
        fn sub_assign(&mut self, other: T) {
            *self = *self - other;
        }
    }

    impl<T> SubAssign<ModInt<T>> for ModInt<T>
    where
        T: PartialOrd + Copy + Add<Output = T> + Sub<Output = T> + Rem<Output = T>,
    {
        fn sub_assign(&mut self, other: ModInt<T>) {
            *self = *self - other;
        }
    }

    impl<T> Mul<ModInt<T>> for ModInt<T>
    where
        T: Mul<Output = T> + Rem<Output = T> + Copy,
    {
        type Output = ModInt<T>;

        fn mul(self, rhs: ModInt<T>) -> ModInt<T> {
            self * rhs.value
        }
    }
    impl<T> Mul<T> for ModInt<T>
    where
        T: Mul<Output = T> + Rem<Output = T> + Copy,
    {
        type Output = ModInt<T>;

        fn mul(self, rhs: T) -> ModInt<T> {
            let t = (self.value * rhs) % self.modulo;
            ModInt {
                value: t,
                modulo: self.modulo,
            }
        }
    }

    impl<T> MulAssign<T> for ModInt<T>
    where
        T: Mul<Output = T> + Rem<Output = T> + Copy,
    {
        fn mul_assign(&mut self, rhs: T) {
            *self = *self * rhs;
        }
    }

    impl<T> MulAssign<ModInt<T>> for ModInt<T>
    where
        T: Mul<Output = T> + Rem<Output = T> + Copy,
    {
        fn mul_assign(&mut self, rhs: ModInt<T>) {
            *self = *self * rhs;
        }
    }

    impl ModInt<usize> {
        pub fn new(value: usize) -> Self {
            ModInt {
                value: value,
                modulo: self::super::MOD,
            }
        }
    }
}

pub struct Scanner<R> {
    reader: 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
            .reader
            .by_ref()
            .bytes()
            .map(|b| b.unwrap())
            .skip_while(|&b| b == b' ' || b == b'\n')
            .take_while(|&b| b != b' ' && b != b'\n')
            .collect::<Vec<_>>();
        unsafe { std::str::from_utf8_unchecked(&buf) }
            .parse()
            .ok()
            .expect("Parse error.")
    }
    pub fn read_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()
    }
}

CODE FESTIVAL 2018 qual A D - 通勤

解法

公式解説を見ながらやった。

地点 i で給油した時、残り容量は必ず f になる。x[i] + f - t までは少なくとも t 以下にはならないので、 x[i] から x[i] + f - t までの間にある給油所は、あってもなくても良い。また、iのあと給油せずにx[i] + fを超えると残量がゼロになってしまうので、x[i]+f-tからx[i]+fの間で必ず給油しなければならない。

dp[i] を i で給油する組み合わせの数とすると、ナイーブな O(N^2) 更新式は以下のように書ける。

for i in 0..n {
    let from = x.upper_bound(x[i] + f - t);
    let to = x.upper_bound(x[i] + f);

    let skip = from - 1 - i;
    let combinations = dp[i] * pow2[skip];

    for j in from..to {
        dp[j] += combinations;
    }
}

これは累積和の性質を使って更新部分を高速化出来る。

コード

use self::mod_int::ModInt;

const MOD: usize = 1e9 as usize + 7;

fn main() {
    let mut sc = Scanner::new();
    let d: usize = sc.read();
    let f: usize = sc.read();
    let t: usize = sc.read();
    let n: usize = sc.read();
    let mut x: Vec<usize> = sc.read_vec(n);

    let mut pow2 = vec![ModInt::new(1); n + 1];
    for i in 0..n {
        pow2[i + 1] = pow2[i] * 2;
    }

    x.insert(0, 0);
    x.push(d);
    let n = x.len();

    let mut dp = vec![ModInt::new(0); n + 1];
    dp[0] = ModInt::new(1);
    let mut sum = vec![ModInt::new(0); n + 1];

    for i in 0..n {
        if i > 0 {
            sum[i] += sum[i - 1];
            dp[i] = sum[i];
        }

        let from = x.upper_bound(x[i] + f - t);
        let to = x.upper_bound(x[i] + f);

        let skip = from - 1 - i;
        let combinations = dp[i] * pow2[skip];

        if from < dp.len() {
            sum[from] += combinations;
        }

        if to < dp.len() {
            sum[to] -= combinations;
        }
    }

    let mut ans = ModInt::new(0);
    for i in 0..(n - 1) {
        if x[n - 1] - x[i] <= f - t {
            let skip = (n - 1) - 1 - i;
            ans += dp[i] * pow2[skip];
        }
    }

    ans += dp[n - 1];
    println!("{}", ans.value);
}

struct Scanner {
    ptr: usize,
    length: usize,
    buf: Vec<u8>,
    small_cache: Vec<u8>,
}

#[allow(dead_code)]
impl Scanner {
    fn new() -> Scanner {
        Scanner {
            ptr: 0,
            length: 0,
            buf: vec![0; 1024],
            small_cache: vec![0; 1024],
        }
    }

    fn load(&mut self) {
        use std::io::Read;
        let mut s = std::io::stdin();
        self.length = s.read(&mut self.buf).unwrap();
    }

    fn byte(&mut self) -> u8 {
        if self.ptr >= self.length {
            self.ptr = 0;
            self.load();
            if self.length == 0 {
                self.buf[0] = b'\n';
                self.length = 1;
            }
        }

        self.ptr += 1;
        return self.buf[self.ptr - 1];
    }

    fn is_space(b: u8) -> bool {
        b == b'\n' || b == b'\r' || b == b'\t' || b == b' '
    }

    fn read_vec<T>(&mut self, n: usize) -> Vec<T>
    where
        T: std::str::FromStr,
        T::Err: std::fmt::Debug,
    {
        (0..n).map(|_| self.read()).collect()
    }

    fn read<T>(&mut self) -> T
    where
        T: std::str::FromStr,
        T::Err: std::fmt::Debug,
    {
        let mut b = self.byte();
        while Scanner::is_space(b) {
            b = self.byte();
        }

        for pos in 0..self.small_cache.len() {
            self.small_cache[pos] = b;
            b = self.byte();
            if Scanner::is_space(b) {
                return String::from_utf8_lossy(&self.small_cache[0..(pos + 1)])
                    .parse()
                    .unwrap();
            }
        }

        let mut v = self.small_cache.clone();
        while !Scanner::is_space(b) {
            v.push(b);
            b = self.byte();
        }
        return String::from_utf8_lossy(&v).parse().unwrap();
    }
}

trait VecBound {
    fn upper_bound(&self, x: usize) -> usize;
}

impl VecBound for Vec<usize> {
    fn upper_bound(&self, x: usize) -> usize {
        self.binary_search_by_key(&(x * 2 + 1), |&v| v * 2)
            .err()
            .unwrap()
    }
}
pub mod mod_int {
    use std::ops::{Add, AddAssign, Mul, MulAssign, Rem, Sub, SubAssign};

    #[derive(Copy)]
    pub struct ModInt<T> {
        pub value: T,
        modulo: T,
    }

    impl<T> Clone for ModInt<T>
    where
        T: Copy,
    {
        fn clone(&self) -> Self {
            ModInt {
                value: self.value,
                modulo: self.modulo,
            }
        }

        fn clone_from(&mut self, source: &ModInt<T>) {
            self.value = source.value;
            self.modulo = source.modulo;
        }
    }

    impl<T> Add<ModInt<T>> for ModInt<T>
    where
        T: Add<Output = T> + Sub<Output = T> + Copy + PartialOrd,
    {
        type Output = ModInt<T>;
        fn add(self, rhs: ModInt<T>) -> ModInt<T> {
            self + rhs.value
        }
    }

    impl<T> Add<T> for ModInt<T>
    where
        T: Add<Output = T> + Sub<Output = T> + Copy + PartialOrd,
    {
        type Output = ModInt<T>;
        fn add(self, rhs: T) -> ModInt<T> {
            let m = self.modulo;
            let mut t = rhs + self.value;
            if t >= m {
                t = t - m;
            }
            ModInt {
                value: t,
                modulo: self.modulo,
            }
        }
    }

    impl<T> Sub<T> for ModInt<T>
    where
        T: PartialOrd + Copy + Add<Output = T> + Sub<Output = T> + Rem<Output = T>,
    {
        type Output = ModInt<T>;
        fn sub(self, rhs: T) -> ModInt<T> {
            let rhs = if rhs >= self.modulo {
                rhs % self.modulo
            } else {
                rhs
            };
            let value = if self.value < rhs {
                self.value + self.modulo
            } else {
                self.value
            };
            ModInt {
                value: value - rhs,
                modulo: self.modulo,
            }
        }
    }

    impl<T> Sub<ModInt<T>> for ModInt<T>
    where
        T: PartialOrd + Copy + Add<Output = T> + Sub<Output = T> + Rem<Output = T>,
    {
        type Output = ModInt<T>;
        fn sub(self, rhs: ModInt<T>) -> ModInt<T> {
            self - rhs.value
        }
    }

    impl<T> AddAssign<T> for ModInt<T>
    where
        T: Add<Output = T> + Sub<Output = T> + Copy + PartialOrd,
    {
        fn add_assign(&mut self, other: T) {
            *self = *self + other;
        }
    }
    impl<T> AddAssign<ModInt<T>> for ModInt<T>
    where
        T: Add<Output = T> + Sub<Output = T> + Copy + PartialOrd,
    {
        fn add_assign(&mut self, other: ModInt<T>) {
            *self = *self + other;
        }
    }

    impl<T> SubAssign<T> for ModInt<T>
    where
        T: PartialOrd + Copy + Add<Output = T> + Sub<Output = T> + Rem<Output = T>,
    {
        fn sub_assign(&mut self, other: T) {
            *self = *self - other;
        }
    }

    impl<T> SubAssign<ModInt<T>> for ModInt<T>
    where
        T: PartialOrd + Copy + Add<Output = T> + Sub<Output = T> + Rem<Output = T>,
    {
        fn sub_assign(&mut self, other: ModInt<T>) {
            *self = *self - other;
        }
    }

    impl<T> Mul<ModInt<T>> for ModInt<T>
    where
        T: Mul<Output = T> + Rem<Output = T> + Copy,
    {
        type Output = ModInt<T>;

        fn mul(self, rhs: ModInt<T>) -> ModInt<T> {
            self * rhs.value
        }
    }
    impl<T> Mul<T> for ModInt<T>
    where
        T: Mul<Output = T> + Rem<Output = T> + Copy,
    {
        type Output = ModInt<T>;

        fn mul(self, rhs: T) -> ModInt<T> {
            let t = (self.value * rhs) % self.modulo;
            ModInt {
                value: t,
                modulo: self.modulo,
            }
        }
    }

    impl<T> MulAssign<T> for ModInt<T>
    where
        T: Mul<Output = T> + Rem<Output = T> + Copy,
    {
        fn mul_assign(&mut self, rhs: T) {
            *self = *self * rhs;
        }
    }

    impl<T> MulAssign<ModInt<T>> for ModInt<T>
    where
        T: Mul<Output = T> + Rem<Output = T> + Copy,
    {
        fn mul_assign(&mut self, rhs: ModInt<T>) {
            *self = *self * rhs;
        }
    }

    impl ModInt<usize> {
        pub fn new(value: usize) -> Self {
            ModInt {
                value: value,
                modulo: super::MOD,
            }
        }
    }
}

AOJ 2893: Balanced Edge Deletion

解法

橋を全列挙し、それぞれについて削除したときの cost を求め、ソートすれば良い。

具体的な実装としては、

  • 橋を列挙する。
  • 橋を含まない連結な部分グラフを潰して 1 つの頂点とし、橋を辺とする木を作る。
  • 木 DP をして、各橋を削除したときのコストを求める。

コード

/// Thank you tanakh!!!
/// https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8
macro_rules! input {
    (source = $s:expr, $($r:tt)*) => {
        let mut iter = $s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
    ($($r:tt)*) => {
        let mut s = {
            use std::io::Read;
            let mut s = String::new();
            std::io::stdin().read_to_string(&mut s).unwrap();
            s
        };
        let mut iter = s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
}

macro_rules! input_inner {
    ($iter:expr) => {};
    ($iter:expr, ) => {};

    ($iter:expr, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($iter, $t);
        input_inner!{$iter $($r)*}
    };
}

macro_rules! read_value {
    ($iter:expr, ( $($t:tt),* )) => {
        ( $(read_value!($iter, $t)),* )
    };

    ($iter:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($iter, $t)).collect::<Vec<_>>()
    };

    ($iter:expr, chars) => {
        read_value!($iter, String).chars().collect::<Vec<char>>()
    };

    ($iter:expr, usize1) => {
        read_value!($iter, usize) - 1
    };

    ($iter:expr, $t:ty) => {
        $iter.next().unwrap().parse::<$t>().expect("Parse error")
    };
}

use std::cmp;
use std::collections::{BTreeMap, BTreeSet};

fn main() {
    input!(n: usize, m: usize, uvw: [(usize1, usize1, usize); m]);

    let mut graph = vec![vec![]; n];
    for &(u, v, _) in uvw.iter() {
        graph[u].push(v);
        graph[v].push(u);
    }

    let mut union_find = UnionFind::new(n);
    let bridges = BridgeDetector::new(&graph)
        .bridges
        .iter()
        .map(|&(u, v)| (cmp::min(u, v), cmp::max(u, v)))
        .collect::<BTreeSet<_>>();
    let mut edges = vec![];
    for &(u, v, w) in uvw.iter() {
        assert!(u < v);
        if bridges.contains(&(u, v)) {
            edges.push((u, v, w));
            continue;
        }
        union_find.unite(u, v);
    }

    let mut convert = BTreeMap::new();
    for i in 0..n {
        let parent = union_find.find(i);
        if convert.contains_key(&parent) {
            continue;
        }
        let n = convert.len();
        convert.insert(parent, n);
    }

    let n = convert.len();
    let mut costs = vec![0; n];
    for &(u, v, w) in uvw.iter() {
        if union_find.find(u) == union_find.find(v) {
            let parent = union_find.find(u);
            let i = *convert.get(&parent).unwrap();
            costs[i] += w;
        }
    }

    let edges = edges
        .iter()
        .map(|&(u, v, w)| {
            let u = union_find.find(u);
            let v = union_find.find(v);
            assert!(u != v);
            let u = *convert.get(&u).unwrap();
            let v = *convert.get(&v).unwrap();
            (u, v, w)
        }).collect::<Vec<_>>();

    let mut graph = vec![vec![]; n];
    for &(u, v, w) in edges.iter() {
        graph[u].push((v, w));
        graph[v].push((u, w));
    }

    dfs(0, 0, &graph, &mut costs);
    let sum = uvw.iter().map(|&(_, _, w)| w).sum::<usize>();
    let mut candidates = uvw
        .iter()
        .map(|&(u, v, w)| {
            if union_find.find(u) == union_find.find(v) {
                (sum - w, u, v)
            } else {
                let fu = *convert.get(&union_find.find(u)).unwrap();
                let fv = *convert.get(&union_find.find(v)).unwrap();
                let cost = cmp::min(costs[fu], costs[fv]);
                let other = sum - cost - w;
                (cmp::max(other, cost) - cmp::min(other, cost), u, v)
            }
        }).collect::<Vec<_>>();
    candidates.sort();
    let (_, u, v) = candidates[0];
    println!("{} {}", u + 1, v + 1);
}

fn dfs(v: usize, parent: usize, graph: &Vec<Vec<(usize, usize)>>, costs: &mut Vec<usize>) -> usize {
    for &(child, w) in graph[v].iter() {
        if child != parent {
            let c = dfs(child, v, graph, costs);
            costs[v] += c + w;
        }
    }
    costs[v]
}

pub struct UnionFind {
    parent: Vec<usize>,
    sizes: Vec<usize>,
    size: usize,
}

impl UnionFind {
    pub fn new(n: usize) -> UnionFind {
        UnionFind {
            parent: (0..n).map(|i| i).collect::<Vec<usize>>(),
            sizes: vec![1; n],
            size: n,
        }
    }

    pub fn find(&mut self, x: usize) -> usize {
        if x == self.parent[x] {
            x
        } else {
            let px = self.parent[x];
            self.parent[x] = self.find(px);
            self.parent[x]
        }
    }

    pub fn unite(&mut self, x: usize, y: usize) -> bool {
        let parent_x = self.find(x);
        let parent_y = self.find(y);
        if parent_x == parent_y {
            return false;
        }

        let (large, small) = if self.sizes[parent_x] < self.sizes[parent_y] {
            (parent_y, parent_x)
        } else {
            (parent_x, parent_y)
        };

        self.parent[small] = large;
        self.sizes[large] += self.sizes[small];
        self.sizes[small] = 0;
        self.size -= 1;
        return true;
    }
}

pub struct BridgeDetector {
    articulations: Vec<usize>,
    bridges: Vec<(usize, usize)>,
    visit: Vec<bool>,
    order: Vec<usize>,
    low_link: Vec<usize>,
    k: usize,
}

impl BridgeDetector {
    pub fn new(graph: &Vec<Vec<usize>>) -> Self {
        let n = graph.len();
        let mut d = BridgeDetector {
            articulations: vec![],
            bridges: vec![],
            visit: vec![false; n],
            order: vec![0; n],
            low_link: vec![0; n],
            k: 0,
        };
        d.run(graph);
        d
    }

    fn run(&mut self, graph: &Vec<Vec<usize>>) {
        let n = graph.len();
        for i in 0..n {
            if !self.visit[i] {
                self.dfs(i, 0, graph, i);
            }
        }
    }

    fn dfs(&mut self, v: usize, previous: usize, graph: &Vec<Vec<usize>>, root: usize) {
        self.visit[v] = true;
        self.order[v] = self.k;
        self.k += 1;
        self.low_link[v] = self.order[v];

        let mut is_articulation = false;
        let mut dimension = 0;
        for &next in graph[v].iter() {
            if !self.visit[next] {
                // The edge (v->next) is not a backedge.
                dimension += 1;
                self.dfs(next, v, graph, root);
                self.low_link[v] = cmp::min(self.low_link[v], self.low_link[next]);
                if v != root && self.order[v] <= self.low_link[next] {
                    is_articulation = true;
                }
                if self.order[v] < self.low_link[next] {
                    let min = cmp::min(v, next);
                    let max = cmp::max(v, next);
                    self.bridges.push((min, max));
                }
            } else if v == root || next != previous {
                // The edge (v->next) is a backedge.
                self.low_link[v] = cmp::min(self.low_link[v], self.order[next]);
            }
        }

        if v == root && dimension > 1 {
            is_articulation = true;
        }
        if is_articulation {
            self.articulations.push(v);
        }
    }
}

AOJ 2891: Namo.. Cut

解法

N 頂点 N 辺のグラフ(いわゆる「なもりグラフ」)は1つだけ閉路があり、その閉路に木がいくつか連結している形になる。各クエリの頂点の両方とも閉路に含まれている場合2本切断する必要があるが、そうでない場合は 1 本切断するだけで非連結に出来る。

コード

/// Thank you tanakh!!!
/// https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8
macro_rules! input {
    (source = $s:expr, $($r:tt)*) => {
        let mut iter = $s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
    ($($r:tt)*) => {
        let mut s = {
            use std::io::Read;
            let mut s = String::new();
            std::io::stdin().read_to_string(&mut s).unwrap();
            s
        };
        let mut iter = s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
}

macro_rules! input_inner {
    ($iter:expr) => {};
    ($iter:expr, ) => {};

    ($iter:expr, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($iter, $t);
        input_inner!{$iter $($r)*}
    };
}

macro_rules! read_value {
    ($iter:expr, ( $($t:tt),* )) => {
        ( $(read_value!($iter, $t)),* )
    };

    ($iter:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($iter, $t)).collect::<Vec<_>>()
    };

    ($iter:expr, chars) => {
        read_value!($iter, String).chars().collect::<Vec<char>>()
    };

    ($iter:expr, usize1) => {
        read_value!($iter, usize) - 1
    };

    ($iter:expr, $t:ty) => {
        $iter.next().unwrap().parse::<$t>().expect("Parse error")
    };
}

use std::collections::VecDeque;

fn main() {
    input!(
        n: usize,
        uv: [(usize1, usize1); n],
        q: usize,
        ab: [(usize1, usize1); q]
    );

    let mut graph = vec![vec![]; n];
    for &(u, v) in uv.iter() {
        graph[u].push(v);
        graph[v].push(u);
    }

    let mut queue = VecDeque::new();
    let mut visit_count = vec![0; n];
    let mut visit = vec![false; n];
    for i in 0..n {
        if graph[i].len() == 1 {
            queue.push_back(i);
            visit[i] = true;
        }
    }

    while let Some(v) = queue.pop_front() {
        for &next in graph[v].iter() {
            if visit[next] {
                continue;
            }
            visit_count[next] += 1;
            if visit_count[next] == graph[next].len() - 1 {
                visit[next] = true;
                queue.push_back(next);
            }
        }
    }

    for &(a, b) in ab.iter() {
        if visit[a] || visit[b] {
            println!("1");
        } else {
            println!("2");
        }
    }
}

ARC094 D - Worst Case

解法

 x(a+1), (x-1)(a+2), ... , 2(a+x-1), a+x が全て ab より小さくなるような x、すなわち、  (x-t)(a+1+t) < ab (0 \leq t \leq x-1) となるような x の最大値を求めたい。  - ( t - \frac{x-a-1}{2} )^2 + \frac{(x+a+1)^2}{4} < ab  (0 \leq t \leq x-1) で x は a より大きいとすると、  \frac{(x+a+1)^2}{4} < ab を満たす x を求めれば良い。

コード

/// Thank you tanakh!!!
///  https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8
macro_rules! input {
    (source = $s:expr, $($r:tt)*) => {
        let mut iter = $s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
    ($($r:tt)*) => {
        let mut s = {
            use std::io::Read;
            let mut s = String::new();
            std::io::stdin().read_to_string(&mut s).unwrap();
            s
        };
        let mut iter = s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
}

macro_rules! input_inner {
    ($iter:expr) => {};
    ($iter:expr, ) => {};

    ($iter:expr, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($iter, $t);
        input_inner!{$iter $($r)*}
    };
}

macro_rules! read_value {
    ($iter:expr, ( $($t:tt),* )) => {
        ( $(read_value!($iter, $t)),* )
    };

    ($iter:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($iter, $t)).collect::<Vec<_>>()
    };

    ($iter:expr, chars) => {
        read_value!($iter, String).chars().collect::<Vec<char>>()
    };

    ($iter:expr, usize1) => {
        read_value!($iter, usize) - 1
    };

    ($iter:expr, $t:ty) => {
        $iter.next().unwrap().parse::<$t>().expect("Parse error")
    };
}

fn main() {
    input!(q: usize, ab: [(usize, usize); q]);
    for &(a, b) in ab.iter() {
        let (a, b) = if a > b { (b, a) } else { (a, b) };
        if a == b {
            println!("{}", 2 * a - 2);
        } else if a + 1 == b {
            println!("{}", 2 * a - 2);
        } else {
            println!("{}", solve2(a, b));
        }
    }
}

fn solve2(a: usize, b: usize) -> usize {
    let mut x = (((a * b) as f64).sqrt() * 2.0) as usize - a - 1;
    let t = if x > a { (x - a - 1) / 2 } else { 0 };
    if (x - t) * (a + 1 + t) >= a * b {
        x -= 1;
    } else if (x - (t + 1)) * (a + 1 + (t + 1)) >= a * b {
        x -= 1;
    }
    a - 1 + x
}

CODE FESTIVAL 2018 qual B E - Game of +-

解法

 1/a (1 \leq a \leq N)を足したり引いたりして 1/lcm(1,2,3,...,N)を作る。

 lcm(1,2,3,...,N)/a(1 \leq a \leq N) を足したり引いたりして 1 を作る。

 G=1 にすることを目指すのではなく  G\equiv 1(\mod lcm(1,2,3,...,N)) にすることを目指す。

 G \equiv 1 (\mod lcm(1,2,3,...,N)) であることは  G \equiv 1 (\mod p)(2\leq p \leq N) である。

 lcm(1,2,3,...,N)/a  \equiv 0 (\mod p)(1 \leq a \leq N, 2\leq p \leq N, a \neq p) なので、各 p について独立に考えればよいということになる。

コード

/// Thank you tanakh!!!
/// https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8
macro_rules! input {
    (source = $s:expr, $($r:tt)*) => {
        let mut iter = $s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
    ($($r:tt)*) => {
        let mut s = {
            use std::io::Read;
            let mut s = String::new();
            std::io::stdin().read_to_string(&mut s).unwrap();
            s
        };
        let mut iter = s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
}

macro_rules! input_inner {
    ($iter:expr) => {};
    ($iter:expr, ) => {};

    ($iter:expr, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($iter, $t);
        input_inner!{$iter $($r)*}
    };
}

macro_rules! read_value {
    ($iter:expr, ( $($t:tt),* )) => {
        ( $(read_value!($iter, $t)),* )
    };

    ($iter:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($iter, $t)).collect::<Vec<_>>()
    };

    ($iter:expr, chars) => {
        read_value!($iter, String).chars().collect::<Vec<char>>()
    };

    ($iter:expr, usize1) => {
        read_value!($iter, usize) - 1
    };

    ($iter:expr, $t:ty) => {
        $iter.next().unwrap().parse::<$t>().expect("Parse error")
    };
}
extern crate num_bigint;
use num_bigint::BigInt;

fn solve(n: usize) -> Vec<(usize, char, usize)> {
    let mut is_prime = vec![true; n + 1];
    is_prime[0] = false;
    is_prime[1] = false;
    for i in 2..(n + 1) {
        if is_prime[i] {
            let mut cur = i * 2;
            while cur <= n {
                is_prime[cur] = false;
                cur += i;
            }
        }
    }

    let primes = (0..(n + 1))
        .filter(|&i| is_prime[i])
        .map(|p| {
            let mut cur = p;
            while cur * p <= n {
                cur *= p;
            }
            cur
        }).collect::<Vec<_>>();
    let addition = primes
        .iter()
        .map(|&prime| {
            let mut cur = 1;
            for &p in primes.iter() {
                if p == prime {
                    continue;
                }
                cur = (cur * p) % prime;
            }
            let add = cur;
            let mut cur = 0;
            let mut count = 0;
            while cur != 1 {
                cur = (cur + add) % prime;
                count += 1;
            }
            count
        }).collect::<Vec<_>>();

    let mut ans = vec![];

    let mut numerator = BigInt::from(0);
    let mut denominator = BigInt::from(1);

    let mut count = 0;
    for i in 0..primes.len() {
        let prime = primes[i];
        let add = addition[i];
        assert!(prime > add);

        let old_denominator = denominator.clone();
        denominator *= prime;
        numerator *= prime;

        if add * 2 > prime {
            let add = prime - add;
            numerator -= old_denominator * add;
            count += add;
            for _ in 0..add {
                ans.push((1, '-', prime));
            }
        } else {
            numerator += old_denominator * add;
            count += add;
            for _ in 0..add {
                ans.push((0, '+', prime));
            }
        }
    }

    let zero = BigInt::from(0);

    while numerator < zero {
        numerator += denominator.clone();
        count += 1;
        ans.push((0, '+', 1));
    }
    while numerator > denominator.clone() {
        numerator -= denominator.clone();
        count += 1;
        ans.push((1, '-', 1));
    }
    assert_eq!(count, ans.len());
    ans.sort();
    ans
}

fn main() {
    input!(n: usize);
    if n == 1 {
        println!("1");
        println!("+ 1");
        return;
    }
    let ans = solve(n);
    println!("{}", ans.len());
    for &(_, c, p) in ans.iter() {
        println!("{} {}", c, p);
    }
}

AOJ 2900: Bumpy Array

解法

 a_i, a_{i+1}, a_{i+2} と並んでいるのを  a_i>a_{i+1} < a_{i+2} としたいが、これが成り立っていないとする。

a_i>a_{i+1} が成り立っている時、  a_i > a_{i+1} > a_{i+2} となっているので、  a_i を動かすことは得にならない。よって  a_{i+1} 以降について問題を解けば良い。

a_i>a_{i+1}が満たされていない時を考える。このとき、 a_i, a_{i+1}, a_{i+2} の大小関係として次の 3 通りが考えられる。

  1. a_i < a_{i+2} < a_{i+1}
  2. a_i < a_{i+1} < a_{i+2}
  3. a_{i+2} < a_i < a_{i+1}

1番目と2番目のケースでは、a_ia_{i+1} を入れ替えることで、 a_{i+1} < a_{i+2} も満たされるので、そのようにする。3番目の場合では、 a_{i+1}a_{i+2} を入れ替えることで、  a_i > a_{i+1} < a_{i+2} が成り立つようになる。これら以外の入れ替え方法では2 つの不等号のうち1つしか満たされず、手数が必ず多くなる。

コード

/// Thank you tanakh!!!
///  https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8
macro_rules! input {
    (source = $s:expr, $($r:tt)*) => {
        let mut iter = $s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
    ($($r:tt)*) => {
        let mut s = {
            use std::io::Read;
            let mut s = String::new();
            std::io::stdin().read_to_string(&mut s).unwrap();
            s
        };
        let mut iter = s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
}

macro_rules! input_inner {
    ($iter:expr) => {};
    ($iter:expr, ) => {};

    ($iter:expr, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($iter, $t);
        input_inner!{$iter $($r)*}
    };
}

macro_rules! read_value {
    ($iter:expr, ( $($t:tt),* )) => {
        ( $(read_value!($iter, $t)),* )
    };

    ($iter:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($iter, $t)).collect::<Vec<_>>()
    };

    ($iter:expr, chars) => {
        read_value!($iter, String).chars().collect::<Vec<char>>()
    };

    ($iter:expr, usize1) => {
        read_value!($iter, usize) - 1
    };

    ($iter:expr, $t:ty) => {
        $iter.next().unwrap().parse::<$t>().expect("Parse error")
    };
}

use std::cmp;

fn solve(mut a: Vec<i64>) -> usize {
    let n = a.len();
    let mut ans = 0;
    for i in 0..(n - 1) {
        if i % 2 == 0 && a[i] < a[i + 1] {
            if i + 2 < n && a[i + 1] > a[i + 2] && a[i] > a[i + 2] {
                a.swap(i + 1, i + 2);
            } else {
                a.swap(i, i + 1);
            }
            ans += 1;
        } else if i % 2 == 1 && a[i] > a[i + 1] {
            if i + 2 < n && a[i + 1] < a[i + 2] && a[i] < a[i + 2] {
                a.swap(i + 1, i + 2);
            } else {
                a.swap(i, i + 1);
            }
            ans += 1;
        }
    }
    ans
}

fn main() {
    input!(n: usize, a: [i64; n]);
    let b: Vec<i64> = a.iter().map(|&i| -i).collect();

    let a1 = solve(a);
    let a2 = solve(b);
    println!("{}", cmp::min(a1, a2));
}