AtCoder Beginner Contest 340 E

https://atcoder.jp/contests/abc340/tasks/abc340_e

入力例1で、初回で2 2 0 5 6になって、2回目は6を取り出して、0に2を1~4に1を足します。このように範囲に同じ値を足すので、そういう木を作ればよいです。

// Mancala 2
#![allow(non_snake_case)]


//////////////////// library ////////////////////

fn read<T: std::str::FromStr>() -> T {
    let mut line = String::new();
    std::io::stdin().read_line(&mut line).ok();
    line.trim().parse().ok().unwrap()
}

fn read_vec<T: std::str::FromStr>() -> Vec<T> {
    read::<String>().split_whitespace()
            .map(|e| e.parse().ok().unwrap()).collect()
}


//////////////////// Segment Tree ////////////////////

struct SegmentTree {
    n: usize,
    m: usize,
    v: Vec<i64>,
}

impl SegmentTree {
    fn add_range(&mut self, a: i64, first: usize, last: usize) {
        if first < last {
            self.add_range_core(a, (first, last), 0, 0, self.n)
        }
    }
    
    fn add_range_core(&mut self, a: i64, range: (usize, usize),
                            i: usize, first: usize, last: usize) {
        let (f, l) = range;
        if f <= first && last <= l {
            self.v[i] += a
        }
        else {
            let mid = (first + last) / 2;
            if f < mid {
                self.add_range_core(a, range, i*2+1, first, mid)
            }
            if mid < l {
                self.add_range_core(a, range, i*2+2, mid, last)
            }
        }
    }
    
    fn get_core(&self, i: usize) -> i64 {
        if i == 0 {
            self.v[i]
        }
        else {
            self.v[i] + self.get_core((i-1)/2)
        }
    }
    
    fn get(&self, i: usize) -> i64 {
        self.get_core(i + self.n - 1)
    }
    
    fn set(&mut self, a: i64, i: usize) {
        let mut j = i + self.n - 1;
        let mut s = 0;
        loop {
            s += self.v[j];
            if j == 0 {
                break
            }
            j = (j-1) / 2;
        }
        self.v[i+self.n-1] += a - s
    }
    
    fn print(&self) {
        println!("{}", (0..self.m).map(|i| self.get(i).to_string()).
                                        collect::<Vec<_>>().join(" "))
    }
    
    fn ceil_two_pow(n: usize) -> usize {
        if n == 1 { 1 } else { SegmentTree::ceil_two_pow((n+1)/2) * 2 }
    }
    
    fn create(A: Vec<i64>) -> SegmentTree {
        let m = A.len();
        let n = SegmentTree::ceil_two_pow(m);
        let mut v: Vec<i64> = vec![0; n*2-1];
        for i in 0..m {
            v[i+n-1] = A[i]
        }
        SegmentTree { n, m, v }
    }
}


//////////////////// process ////////////////////

fn read_input() -> (Vec<i64>, Vec<usize>) {
    let _v: Vec<usize> = read_vec();
    let A = read_vec();
    let B = read_vec();
    (A, B)
}

fn F(A: Vec<i64>, B: Vec<usize>) {
    let N = A.len();
    let mut tree = SegmentTree::create(A);
    for b in B.into_iter() {
        let C = tree.get(b);
        tree.set(0, b);
        let i = (b + 1) % N;
        let q = C / (N as i64) ;
        let r = (C as usize) % N;
        if i + r <= N {
            tree.add_range(q, 0, i);
            tree.add_range(q+1, i, i+r);
            tree.add_range(q, i+r, N)
        }
        else {
            tree.add_range(q+1, 0, i+r-N);
            tree.add_range(q, i+r-N, i);
            tree.add_range(q+1, i, N)
        }
    }
    tree.print()
}

fn main() {
    let (A, B) = read_input();
    F(A, B)
}

AtCoder Beginner Contest 340 D

https://atcoder.jp/contests/abc340/tasks/abc340_d

単なるダイクストラ法です。
隣が2つと決まっているので、グラフをVecにしやすいです。

// Super Takahashi Bros.
#![allow(non_snake_case)]


//////////////////// library ////////////////////

fn read<T: std::str::FromStr>() -> T {
    let mut line = String::new();
    std::io::stdin().read_line(&mut line).ok();
    line.trim().parse().ok().unwrap()
}

fn read_vec<T: std::str::FromStr>() -> Vec<T> {
    read::<String>().split_whitespace()
            .map(|e| e.parse().ok().unwrap()).collect()
}


//////////////////// Graph ////////////////////

struct Graph {
    vs: Vec<usize>
}

impl Graph {
    fn len(&self) -> usize {
        self.vs.len() / 4
    }
    
    fn is_end(&self, v: usize) -> bool {
        self.vs[v*4-4] == 0
    }
    
    fn neighbors(&self, v: usize) -> Vec<(usize, usize)> {
        let mut neis: Vec<(usize, usize)> = vec![];
        if !self.is_end(v) {
            neis.push((self.vs[v*4-4], self.vs[v*4-3]));
            neis.push((self.vs[v*4-2], self.vs[v*4-1]))
        }
        neis
    }
    
    fn create(edges: Vec<(usize, usize, usize)>) -> Graph {
        let N = edges.len() + 1;
        let mut vs: Vec<usize> = vec![0; N*4];
        for i in 0..N-1 {
            vs[i*4] = i+2;
            let (A, B, X) = edges[i];
            vs[i*4+1] = A;
            vs[i*4+2] = X;
            vs[i*4+3] = B
        }
        Graph { vs }
    }
}


//////////////////// Dijkstra ////////////////////

use std::collections::BinaryHeap;

#[derive(Debug, Eq, PartialEq)]
struct Item {
    dist: usize,
    node: usize,
}

impl Ord for Item {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        other.dist.cmp(&self.dist)
    }
}

impl PartialOrd for Item {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

fn Dijkstra(graph: Graph, v0: usize, v1: usize) -> usize {
    let mut heap = BinaryHeap::new();
    heap.push(Item { dist: 0, node: v0 });
    let N = graph.len();
    let mut visited: Vec<bool> = vec![false; N];
    while let Some(v) = heap.pop() {
        if visited[v.node-1] {
            continue
        }
        else {
            visited[v.node-1] = true
        }
        
        if v.node == v1 {
            return v.dist
        }
        
        let neis = graph.neighbors(v.node);
        for (v2, d2) in neis.into_iter() {
            if !visited[v2-1] {
                heap.push(Item { dist: v.dist+d2, node: v2 })
            }
        }
    }
    0
}


//////////////////// process ////////////////////

fn read_input() -> Vec<(usize, usize, usize)> {
    let N: usize = read();
    let edges: Vec<(usize, usize, usize)> = (0..N-1).map(|_| read_vec()).
                                            map(|v| (v[0], v[1], v[2])).
                                            collect();
    edges
}

fn F(edges: Vec<(usize, usize, usize)>) -> usize {
    let graph = Graph::create(edges);
    let N = graph.len();
    Dijkstra(graph, 1, N)
}

fn main() {
    let edges = read_input();
    println!("{}", F(edges))
}

AtCoder Beginner Contest 339 E

https://atcoder.jp/contests/abc339/tasks/abc339_e

簡単なDPです。 A_iまで最大の列の長さを dp_{A_i}とすると、
 dp_{A_i} = \max \{dp_{A_j}| j \lt i, A_i-D \le A_j \le A_i+D \} + 1
となります。ただ、このままだと計算量が O(N^2)で間に合わないので、範囲の最大値を取れる木を用意します。

// Smooth Subsequence
#![allow(non_snake_case)]

use std::cmp::max;


//////////////////// library ////////////////////

fn read<T: std::str::FromStr>() -> T {
    let mut line = String::new();
    std::io::stdin().read_line(&mut line).ok();
    line.trim().parse().ok().unwrap()
}

fn read_vec<T: std::str::FromStr>() -> Vec<T> {
    read::<String>().split_whitespace()
            .map(|e| e.parse().ok().unwrap()).collect()
}


//////////////////// Segment Tree ////////////////////

struct SegmentTree {
    n: usize,
    v: Vec<i32>,
}

impl SegmentTree {
    fn ceil_two_pow(n: usize) -> usize {
        if n == 1 { 1 } else { SegmentTree::ceil_two_pow((n+1)/2) * 2 }
    }
    
    fn max_range(&self, range: (usize, usize)) -> i32 {
        self.max_range_core(range, 0, 1, self.n+1)
    }
    
    fn max_range_core(&self, range: (usize, usize),
                        i: usize, first: usize, last: usize) -> i32 {
        let (f, l) = range;
        if f <= first && last <= l {
            self.v[i]
        }
        else {
            let mid = (first + last) / 2;
            let m1 = if f < mid {
                        self.max_range_core(range, i*2+1, first, mid)
                    } else { 0 };
            let m2 = if mid < l {
                        self.max_range_core(range, i*2+2, mid, last)
                    } else { 0 };
            max(m1, m2)
        }
    }
    
    // set v to i
    fn set(&mut self, i: usize, v: i32) {
        let mut j = i + self.n - 1;
        if j >= self.n {
            self.v[j-1] = v
        }
        while j > 1 {
            j >>= 1;
            self.v[j-1] = max(self.v[j-1], v)
        }
    }
    
    fn create(m: usize) -> SegmentTree {
        let n = SegmentTree::ceil_two_pow(m);
        let v: Vec<i32> = vec![0; n*2-1];
        SegmentTree { n, v }
    }
}


//////////////////// process ////////////////////

fn read_input() -> (usize, Vec<usize>) {
    let v: Vec<usize> = read_vec();
    let D = v[1];
    let A: Vec<usize> = read_vec();
    (D, A)
}

fn get_range(a: usize, D: usize, M: usize) -> (usize, usize) {
    let first = if a < D + 1 { 1 } else { a - D };
    let last = if a + D > M { M + 1 } else { a + D + 1 };
    (first, last)
}

fn F(D: usize, A: Vec<usize>) -> i32 {
    let M = *A.iter().max().unwrap();
    let mut tree = SegmentTree::create(M);
    for a in A.into_iter() {
        let s = tree.max_range(get_range(a, D, M));
        tree.set(a, s+1)
    }
    tree.max_range((1, M+1))
}

fn main() {
    let (D, A) = read_input();
    println!("{}", F(D, A))
}

AtCoder Beginner Contest 339 D

https://atcoder.jp/contests/abc339/tasks/abc339_d

二人のプレーヤーの位置を状態としたDPですね。最初、HashMapを使っていたのですが、実行時間ががギリギリで、4次元の配列に直したら速くなりました。

// Synchronized Players
#![allow(non_snake_case)]


//////////////////// library ////////////////////

fn read<T: std::str::FromStr>() -> T {
    let mut line = String::new();
    std::io::stdin().read_line(&mut line).ok();
    line.trim().parse().ok().unwrap()
}


//////////////////// State ////////////////////

type Position = (usize, usize);
type State = (Position, Position);


//////////////////// Board ////////////////////

#[derive(PartialEq)]
enum PosState {
    Player,
    Vacant,
    Object,
}

struct Board {
    S: Vec<Vec<char>>
}

impl Board {
    fn size(&self) -> usize {
        self.S.len()
    }
    
    fn get_state(&self, pos: Position) -> PosState {
        let (x, y) = pos;
        match self.S[x][y] {
            '#' => PosState::Object,
            'P' => PosState::Player,
            _   => PosState::Vacant,
        }
    }
    
    fn is_vacant(&self, pos: Position) -> bool {
        self.get_state(pos) != PosState::Object
    }
    
    fn next_position(&self, pos: Position) -> Option<Position> {
        let (x, y) = pos;
        let N = self.size();
        if y == N-1 {
            if x == N-1 { None } else { Some((x+1, 0)) }
        }
        else {
            Some((x, y+1))
        }
    }
    
    fn find_player(&self, start_pos: Position) -> Option<Position> {
        let mut pos = start_pos;
        loop {
            match self.get_state(pos) {
                PosState::Player => { return Some(pos) },
                _                => ()
            }
            if let Some(pos1) = self.next_position(pos) {
                pos = pos1
            }
            else {
                break
            }
        }
        None
    }
    
    fn positions(&self) -> State {
        let p1 = self.find_player((0, 0));
        let p2 = self.find_player(self.next_position(p1.unwrap()).unwrap());
        if p1.unwrap() <= p2.unwrap() {
            (p1.unwrap(), p2.unwrap())
        }
        else {
            (p2.unwrap(), p1.unwrap())
        }
    }
    
    fn move_player(&self, p: Position, dir: (i32, i32)) -> Position {
        let (x, y) = p;
        let p1 = match dir {
            (-1, 0) => if x == 0 { p } else { (x-1, y) },
            (1, 0)  => if x == self.size()-1 { p } else { (x+1, y) },
            (0, -1) => if y == 0 { p } else { (x, y-1) },
            _       => if y == self.size()-1 { p } else { (x, y+1) }
        };
        if self.is_vacant(p1) { p1 } else { p }
    }
    
    fn move_players(&self, state: State, dir: (i32, i32)) -> State {
        let p1 = self.move_player(state.0, dir);
        let p2 = self.move_player(state.1, dir);
        (p1, p2)
    }
    
    fn read() -> Board {
        let N: usize = read();
        let S: Vec<Vec<char>> =
                (0..N).map(|_| read::<String>().chars().collect()).collect();
        Board { S }
    }
}


//////////////////// process ////////////////////

type DP = Vec<Vec<Vec<Vec<i32>>>>;
const INF: i32 = 1000000000;

fn get_value(state: State, dp: &DP) -> i32 {
    let ((x1, y1), (x2, y2)) = state;
    dp[x1][y1][x2][y2]
}

fn set_value(state: State, v: i32, dp: &mut DP) {
    let ((x1, y1), (x2, y2)) = state;
    dp[x1][y1][x2][y2] = v
}

fn initialize_DP(state: State, N: usize) -> DP {
    let mut dp: DP = vec![vec![vec![vec![INF; N]; N]; N]; N];
    set_value(state, 0, &mut dp);
    dp
}

fn update_DP(state: State, dp: &mut DP, board: &Board) -> Vec<State> {
    let s = get_value(state, &dp);
    let mut new_states: Vec<State> = vec![];
    let dirs: Vec<(i32, i32)> = vec![(-1, 0), (1, 0), (0, -1), (0, 1)];
    for dir in dirs.into_iter() {
        let state1 = board.move_players(state, dir);
        if get_value(state1, &dp) == INF {
            set_value(state1, s+1, dp);
            new_states.push(state1)
        }
    }
    new_states
}

use std::collections::VecDeque;

fn F(board: Board) -> i32 {
    let init_state = board.positions();
    let mut dp: DP = initialize_DP(init_state, board.size());
    let mut queue = VecDeque::new();
    queue.push_back(init_state);
    while let Some(state) = queue.pop_front() {
        let new_states = update_DP(state, &mut dp, &board);
        for s in new_states.into_iter() {
            queue.push_back(s);
            let (p1, p2) = s;
            if p1 == p2 {
                return get_value(s, &dp)
            }
        }
    }
    -1
}

fn main() {
    let board = Board::read();
    println!("{}", F(board))
}

AtCoder Beginner Contest 338 E

https://atcoder.jp/contests/abc338/tasks/abc338_e

A < Bとして、Aが小さい弧から見ていって、Aが前のBを超えない限り、Bをスタックしていきます。

// Chord
#![allow(non_snake_case)]

use std::cmp::{min, max};


//////////////////// library ////////////////////

fn read<T: std::str::FromStr>() -> T {
    let mut line = String::new();
    std::io::stdin().read_line(&mut line).ok();
    line.trim().parse().ok().unwrap()
}

fn read_vec<T: std::str::FromStr>() -> Vec<T> {
    read::<String>().split_whitespace()
            .map(|e| e.parse().ok().unwrap()).collect()
}

fn YesNo(b: bool) -> String {
    return if b { "Yes" } else { "No" }.to_string()
}


//////////////////// process ////////////////////

type Chord = (usize, usize);

fn read_chord() -> Chord {
    let v: Vec<usize> = read_vec();
    (v[0], v[1])
}

fn read_input() -> Vec<Chord> {
    let N: usize = read();
    let chords: Vec<Chord> = (0..N).map(|_| read_chord()).collect();
    chords
}

fn sort_chords(chords_: Vec<Chord>) -> Vec<Chord> {
    let mut chords: Vec<Chord> = chords_.into_iter().
                                        map(|(A, B)| (min(A, B), max(A, B))).
                                        collect();
    chords.sort_by_key(|&(A, _)| A);
    chords
}

fn F(chords_: Vec<Chord>) -> bool {
    let N = chords_.len();
    let chords = sort_chords(chords_);
    let mut stack = vec![chords[0].1];
    for i in 1..N {
        let (A1, B1) = chords[i];
        while !stack.is_empty() {
            let B = stack[stack.len()-1];
            if A1 < B {
                if B1 > B {
                    return true
                }
                else {
                    stack.push(B1);
                    break
                }
            }
            else {
                stack.pop();
            }
        }
        if stack.is_empty() {
            stack.push(B1)
        }
    }
    false
}

fn main() {
    let chords = read_input();
    println!("{}", YesNo(F(chords)))
}

AtCoder Beginner Contest 338 D

https://atcoder.jp/contests/abc338/tasks/abc338_d

一歩ずつ進みます。例1だとまず1から3ですが、封鎖した橋が1か2なら長さ1、3なら長さ2です。次に3から2ですが、封鎖した橋が1か3なら長さ1、2なら長さ2です。このように同じ長さが続くので、セグメント木を作って、ある範囲に同じ長さを足します。

// Island Tour
#![allow(non_snake_case)]

use std::cmp::{min, max};


//////////////////// library ////////////////////

fn read<T: std::str::FromStr>() -> T {
    let mut line = String::new();
    std::io::stdin().read_line(&mut line).ok();
    line.trim().parse().ok().unwrap()
}

fn read_vec<T: std::str::FromStr>() -> Vec<T> {
    read::<String>().split_whitespace()
            .map(|e| e.parse().ok().unwrap()).collect()
}


//////////////////// Segment Tree ////////////////////

const INF: i64 = 10_i64.pow(18);

struct SegmentTree {
    n: usize,
    v: Vec<i64>,
}

impl SegmentTree {
    fn ceil_two_pow(n: usize) -> usize {
        if n == 1 { 1 } else { SegmentTree::ceil_two_pow((n+1)/2) * 2 }
    }
    
    fn create(m: usize) -> SegmentTree {
        let n = SegmentTree::ceil_two_pow(m);
        let mut v: Vec<i64> = vec![0; n*2-1];
        for i in n+m-1..n*2-1 {
            v[i] = INF
        }
        SegmentTree { n, v }
    }
    
    fn add_range(&mut self, i: usize, j: usize, v_: usize) {
        let v: i64 = v_ as i64;
        self.add(j, v);
        self.sub(i-1, v)
    }
    
    // add v to [1, right]
    fn add(&mut self, right: usize, v: i64) {
        let mut i = right + self.n;
        if right == self.n {
            self.v[0] += v
        }
        while i > 1 {
            if (i & 1) == 1 {
                self.v[i-2] += v
            }
            i >>= 1
        }
    }
    
    // subtract v to [1, right]
    fn sub(&mut self, right: usize, v: i64) {
        let mut i = right + self.n;
        if right == self.n {
            self.v[0] -= v
        }
        while i > 1 {
            if (i & 1) == 1 {
                self.v[i-2] -= v
            }
            i >>= 1
        }
    }
    
    fn min(&self) -> i64 {
        self.min_core(0)
    }
    
    fn min_core(&self, i: usize) -> i64 {
        if i >= self.n - 1 {
            self.v[i]
        }
        else {
            self.v[i] + min(self.min_core(i*2+1), self.min_core(i*2+2))
        }
    }
}


//////////////////// process ////////////////////

fn read_input() -> (usize, Vec<usize>) {
    let v = read_vec();
    let N = v[0];
    let X = read_vec();
    (N, X)
}

fn F(N: usize, X: Vec<usize>) -> i64 {
    let mut raq = SegmentTree::create(N);
    for i in 0..X.len()-1 {
        let u = min(X[i], X[i+1]);
        let v = max(X[i], X[i+1]);
        if u == 1 {
            raq.add_range(1, v-1, N-v+1);
            raq.add_range(v, N, v-1);
        }
        else if v == N {
            raq.add_range(1, u-1, N-u);
            raq.add_range(u, N-1, u);
            raq.add_range(N, N, N-u)
        }
        else {
            raq.add_range(1, u-1, v-u);
            raq.add_range(u, v-1, N-v+u);
            raq.add_range(v, N, v-u)
        }
    }
    raq.min()
}

fn main() {
    let (N, X) = read_input();
    println!("{}", F(N, X))
}

MojoでProject Euler 15

https://projecteuler.net/problem=15

Combinationの計算をすればよいですが、あえてDPで計算しています。Matrix構造体を1次元ベクトルで表現しています。

import sys


#################### Matrix ####################

struct Matrix:
    var H: Int
    var W: Int
    var A: DynamicVector[Int]
    
    fn __init__(inout self, H: Int, W: Int):
        self.H = H
        self.W = W
        self.A = DynamicVector[Int]()
        self.A.resize(H*W, 0)
    
    fn __getitem__(self, i: Int, j: Int) -> Int:
        return self.A[i*self.W+j]
    
    fn __setitem__(inout self, i: Int, j: Int, e: Int):
        self.A[i*self.W+j] = e


#################### process ####################

fn f(H: Int, W: Int) -> Int:
    var dp = Matrix(H+1, W+1)
    dp[0, 0] = 1
    for x in range(H+1):
        for y in range(W+1):
            if x >= 1:
                dp[x, y] += dp[x-1, y]
            if y >= 1:
                dp[x, y] += dp[x, y-1]
    return dp[H, W]

fn main() raises:
    let args = sys.argv()
    let H = atol(args[1])
    let W = atol(args[2])
    print(f(H, W))