AtCoder Beginner Contest 285 D

https://atcoder.jp/contests/abc285/tasks/abc285_d

(S, T)をエッジとしてグラフにします。それがループを含まないか調べます。少し前に連結成分に分けるコードを書いたので、連結成分に分けて、それぞれの成分が木になっているかを調べます。

// Change Usernames
#![allow(non_snake_case)]

use std::collections::{HashMap, HashSet};


//////////////////// 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".to_string() } else { "No".to_string() }
}


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

struct Graph {
    g: HashMap<usize, Vec<usize>>
}

impl Graph {
    fn num_nodes(&self) -> usize {
        self.g.len()
    }
    
    fn num_edges(&self) -> usize {
        self.g.iter().map(|(_, vs)| vs.len()).sum::<usize>() / 2
    }
    
    fn divide_into_connected(&self) -> Vec<Graph> {
        let mut subgraphs = Vec::<Graph>::new();
        let mut unvisited = self.g.keys().map(|v| *v).
                                    collect::<HashSet<usize>>();
        while !unvisited.is_empty() {
            let v0 = unvisited.iter().next().unwrap();
            let mut g = HashMap::<usize, Vec<usize>>::new();
            let mut stack: Vec<usize> = vec![*v0];
            while !stack.is_empty() {
                let v = stack.pop().unwrap();
                let vs = self.g.get(&v).unwrap();
                let vs_copy = vs.iter().map(|v1| *v1).
                                        collect::<Vec<usize>>();
                g.insert(v, vs_copy);
                unvisited.remove(&v);
                for v1 in vs.iter() {
                    if unvisited.contains(v1) {
                        stack.push(*v1);
                        unvisited.remove(v1);
                    }
                }
            }
            subgraphs.push(Graph { g })
        }
        subgraphs
    }
}


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

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

fn make_graph(edges: Vec<(String, String)>) -> Graph {
    let vs = edges.iter().
                map(|(v1, v2)| vec![v1.to_string(), v2.to_string()]).
                flatten().collect::<HashSet<String>>();
    let dic = vs.into_iter().enumerate().map(|(i, key)| (key, i)).
                                collect::<HashMap<String, usize>>();
    let mut g = HashMap::<usize, Vec<usize>>::new();
    for (v1, v2) in edges.iter() {
        let i1 = dic.get(v1).unwrap();
        let i2 = dic.get(v2).unwrap();
        let e1 = g.entry(*i1).or_insert(vec![]);
        (*e1).push(*i2);
        let e2 = g.entry(*i2).or_insert(vec![]);
        (*e2).push(*i1);
    }
    Graph { g }
}

fn f(edges: Vec<(String, String)>) -> bool {
    let graph = make_graph(edges);
    let subgraphs = graph.divide_into_connected();
    subgraphs.iter().all(|g| g.num_nodes() == g.num_edges() + 1)
}

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

AtCoder Beginner Contest 265 D

https://atcoder.jp/contests/abc265/tasks/abc265_d

各解はしゃくとり法で求められるので、その解をたどっていきます。

// Iroha and Haiku (New ABC Edition)
#![allow(non_snake_case)]

use std::collections::HashMap;


//////////////////// 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".to_string() } else { "No".to_string() }
}


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

fn read_input() -> (Vec<i64>, Vec<i64>) {
    let v = read_vec();
    let P: i64 = v[1];
    let Q: i64 = v[2];
    let R: i64 = v[3];
    let A: Vec<i64> = read_vec();
    (vec![P, Q, R], A)
}

fn accumulate(A: Vec<i64>) -> Vec<i64> {
    let mut B: Vec<i64> = Vec::new();
    B.push(0);
    let mut acc = 0;
    for a in A.into_iter() {
        acc += a;
        B.push(acc)
    }
    B
}

fn solve_each(S: i64, B: &Vec<i64>) -> Vec<(usize, usize)> {
    let mut kls: Vec<(usize, usize)> = Vec::new();
    let N = B.len();
    let mut k: usize = 0;
    let mut l: usize = 1;
    while l < N {
        if S == B[l] - B[k] {
            kls.push((k, l));
            k += 1;
            l += 1
        }
        else if S > B[l] - B[k] {
            l += 1
        }
        else {
            k += 1
        }
    }
    kls
}

fn walk(vs0: Vec<usize>, i: usize, v: Vec<i64>, B: Vec<i64>) -> bool {
    if i == v.len() {
        return !vs0.is_empty()
    }
    
    let mut vs : Vec<usize> = Vec::new();
    let range = solve_each(v[i], &B);
    let dic: HashMap<usize, usize> = range.iter().map(|&v| v).collect();
    for v0 in vs0.iter() {
        match dic.get(v0) {
            Some(v1) => vs.push(*v1),
            None     => ()
        }
    }
    walk(vs, i + 1, v, B)
}

fn f(v: Vec<i64>, A: Vec<i64>) -> bool {
    let B = accumulate(A);
    let vs0: Vec<usize> = (0..B.len()).collect();
    walk(vs0, 0, v, B)
}

fn main() {
    let (v, A) = read_input();
    println!("{}", YesNo(f(v, A)))
}

AtCoder Beginner Contest 266 D

https://atcoder.jp/contests/abc266/tasks/abc266_d

各すぬけ君が現れる時刻に各穴での最大値を記憶していけばよいですね。
穴の数が固定なので、ここでは配列を使っています。
定数はこんな感じに定義します。

const M: usize = 5;

配列はこう初期化します。

let mut new_dp: [usize; M] = [0; M];

0がM個の配列です。Mが定数だからこうできるわけですね。

// Snuke Panic (1D)
#![allow(non_snake_case)]

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

const M: usize = 5;


//////////////////// 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()
}


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

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

fn update(dp: [usize; M], T0: &usize, T: &usize,
                            X: &usize, A: &usize) -> [usize; M] {
    let mut new_dp: [usize; M] = [0; M];
    for i in 0..M {
        new_dp[i] = dp[i]
    }
    
    for from in 0..min(T0+1, M) {
        let dT = T - T0;
        let min_to = if from < dT { 0 } else { from - dT };
        let max_to = if M - from <= dT { M - 1 } else { from + dT };
        for to in min_to..(max_to+1) {
            if to == *X {
                new_dp[to] = max(dp[from] + A, new_dp[to])
            }
            else {
                new_dp[to] = max(dp[from], new_dp[to])
            }
        }
    }
    new_dp
}

fn f(v: Vec<(usize, usize, usize)>) -> usize {
    let mut dp: [usize; M] = [0; M];
    dp = update(dp, &0, &v[0].0, &v[0].1, &v[0].2);
    for ((T0, _, _), (T, X, A)) in v.iter().zip(&v[1..]) {
        dp = update(dp, T0, T, X, A)
    }
    *dp.iter().max().unwrap()
}

fn main() {
    let v = read_input();
    println!("{}", f(v))
}

AtCoder Beginner Contest 267 D

https://atcoder.jp/contests/abc267/tasks/abc267_d

各Aに対して部分列の長さごとに最大値を求めればよいです。

// Index × A(Not Continuous ver.)
#![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()
}


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

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

fn update(a: &i64, i: usize, dp: Vec<i64>) -> Vec<i64> {
    let mut new_dp = dp.to_vec();
    for j in 0..(min(i+1, dp.len()-1)) {
        let val = dp[j] + a * ((j+1) as i64);
        new_dp[j+1] = if j == i { val } else { max(val, dp[j+1]) }
    }
    new_dp
}

fn f(M: usize, A: Vec<i64>) -> i64 {
    let mut dp: Vec<i64> = (0..(M+1)).map(|_| 0).collect();
    for (i, a) in A.iter().enumerate() {
        dp = update(a, i, dp);
    }
    dp[M]
}

fn main() {
    let (M, A) = read_input();
    println!("{}", f(M, A))
}

AtCoder Beginner Contest 284 D

https://atcoder.jp/contests/abc284/tasks/abc284_d

 N^{1/3}までにpかqのどちらかで割り切れます。
qで割り切れたら、 \sqrt{N/q}を計算します。 \sqrt{M}の計算はニュートン法的に、
 s_0 = n,  s_{n+1} = \lfloor(M + \frac{M}{s_{n}})/2\rfloorを収束するまで繰り返します。

// Happy New Year 2023
#![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()
}


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

fn read_input() -> Vec<u64> {
    let T: usize = read();
    (0..T).map(|_| read()).collect::<Vec<u64>>()
}

fn int_sqrt_core(u: u64, s0: u64) -> u64 {
    let s = (s0 + u / s0) / 2;
    if s >= s0 {
        s0
    }
    else {
        int_sqrt_core(u, s)
    }
}

fn int_sqrt(n: u64) -> u64 {
    int_sqrt_core(n, n)
}

fn f(n: u64) -> (u64, u64) {
    for p1 in 2u64.. {
        if n % p1 == 0 {
            if n % (p1 * p1) == 0 {
                return (p1, n / (p1 * p1))
            }
            else {
                let q = p1;
                return (int_sqrt(n / q), q)
            }
        }
    }
    (0, 0)  // ここには来ないが要る
}

fn main() {
    let N = read_input();
    for n in N.into_iter() {
        let (p, q) = f(n);
        println!("{} {}", p, q)
    }
}

AtCoder Beginner Contest 268 D

https://atcoder.jp/contests/abc268/tasks/abc268_d

Sの間にアンダースコアを挟みますが、例えば、Sが4個で合わせて11文字だったら、最大5個のアンダースコアを3つに分配することになります。これは意外と簡単です。最初は、

1 1 1

これに1ずつ加えていけばよいです。例えば、

2 1 1

です。しかし、うまく加えてあげないと重複することになります。自由に加えられたら、

1 2 1

からも、

2 1 1

からも、

2 2 1

とすることができます。こういうときは逆から考えます。

2 2 1

から1個減らすには、

2 1 1

が自然でしょう。要するに、1より大きい右端から減らすのです。逆に戻すと、追加できるのは、右から辿っていって、1が続く間はどこでも追加できる、1より大きい数に出合ったらそこには追加できてもう左には追加できない、とすればよいです。
場合によっては複数追加できる箇所があるので、Queueを使います。QueueはVecDequeを使います。
permutationsもそんなに難しくないので実装しました。

// Unique Username
#![allow(non_snake_case)]

use std::collections::{VecDeque, HashSet};


//////////////////// 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()
}


//////////////////// Distribute ////////////////////

struct Distribute {
    n: usize,
    m: usize,
    queue: VecDeque<Vec<usize>>,
}

impl Iterator for Distribute {
    type Item = Vec<usize>;
    
    fn next(& mut self) -> Option<Vec<usize>> {
        let v_ = self.queue.pop_front();
        if v_ == None {
            return None
        }
        
        let v0 = v_.unwrap();
        if v0.iter().sum::<usize>() == self.n {
            return Some(v0)
        }
        
        for i in (0..self.m).rev() {
            if i == self.m - 1 {
                // 右端なら積める
                let v = Distribute::add(&v0, i);
                self.queue.push_back(v);
                if v0[i] > 1 {
                    break
                }
            }
            else if v0[i] > 1 {
                // 1でない最も右に積める
                let v = Distribute::add(&v0, i);
                self.queue.push_back(v);
                break
            }
            else {
                // 1でも積める
                let v = Distribute::add(&v0, i);
                self.queue.push_back(v);
            }
        }
        return Some(v0)
    }
}

impl Distribute {
    fn add(v: &Vec<usize>, i: usize) -> Vec<usize> {
        let mut v1 = v.to_vec();
        v1[i] += 1;
        v1
    }
    
    fn create(n: usize, m: usize) -> Distribute {
        let mut q = VecDeque::<Vec<usize>>::new();
        let v = (0..m).map(|_| 1).collect::<Vec<usize>>();
        q.push_back(v);
        Distribute { n, m, queue: q }
    }
}


//////////////////// Permutations ////////////////////

struct Permutations {
    a: Vec<usize>
}

impl Iterator for Permutations {
    type Item = Vec<usize>;
    
    fn next(&mut self) -> Option<Vec<usize>> {
        if self.a.is_empty() {
            return None
        }
        
        let ret = Some(self.a.to_vec());
        for i in (1..self.a.len()).rev() {
            if self.a[i-1] < self.a[i] {
                self.change(i);
                return ret
            }
        }
        self.a.clear();
        ret
    }
}

impl Permutations {
    fn swap(&mut self, i: usize, j: usize) {
        let tmp = self.a[i];
        self.a[i] = self.a[j];
        self.a[j] = tmp;
    }
    
    fn find_neighbor_index(&mut self, i: usize) -> usize {
        for j in i..self.a.len() {
            if self.a[i-1] > self.a[j] {
                return j - 1
            }
        }
        self.a.len() - 1
    }
    
    fn change(&mut self, i: usize) {
        let k = self.find_neighbor_index(i);
        self.swap(i - 1, k);
        for j in i..(i+(self.a.len()-i)/2) {
            self.swap(j, self.a.len() - j + i - 1)
        }
    }
    
    fn create(n: usize) -> Permutations {
        let a = (0..n).collect::<Vec<usize>>();
        Permutations { a }
    }
}


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

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

fn shuffle(a: &Vec<usize>, v: &Vec<String>) -> Vec<String> {
    a.iter().map(|i| v[*i].to_string()).collect::<Vec<String>>()
}

fn join(v: &Vec<String>, ds: Vec<usize>) -> String {
    let mut w = Vec::<String>::new();
    w.push(v[0].to_string());
    for i in 0..ds.len() {
        w.push((0..ds[i]).map(|_| '_').collect::<String>());
        w.push(v[i+1].to_string())
    }
    w.join("")
}

fn f(S: Vec<String>, T: Vec<String>) -> String {
    let total_len = S.iter().map(|s| s.len()).sum::<usize>();
    let res = 16 - total_len;
    let set_T: HashSet<String> = T.iter().map(|t| t.to_string()).collect();
    for a in Permutations::create(S.len()) {
        let v = shuffle(&a, &S);
        for ds in Distribute::create(res, S.len() - 1) {
            let user_name = join(&v, ds);
            if user_name.len() < 3 {
                continue
            }
            if !set_T.contains(&user_name) {
                return user_name
            }
        }
    }
    "-1".to_string()
}

fn main() {
    let (S, T) = read_input();
    println!("{}", f(S, T))
}

AtCoder Beginner Contest 269 D

https://atcoder.jp/contests/abc269/tasks/abc269_d

グラフを連結成分に分けます。グラフの表現にはHashMapを使います。Vecでも表せるのですが、連結成分に分けるとなると効率が悪くなります。実際には分ける必要は無いのですが、後で使うために分けるコードを書きました。

// Do use hexagon grid
#![allow(non_snake_case)]

use std::ops::Add;
use std::collections::{HashSet, HashMap};


//////////////////// 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()
}


//////////////////// Point ////////////////////

#[derive(Clone, Copy)]
#[derive(Debug)]
#[derive(Eq, Hash, PartialEq)]
struct Point {
    x: i32,
    y: i32,
}

impl Add for Point {
    type Output = Self;
    
    fn add(self, other: Self) -> Self {
        Self { x: self.x + other.x, y: self.y + other.y }
    }
}


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

struct Graph {
    g: HashMap<usize, Vec<usize>>
}

impl Graph {
    fn divide_into_connected(&self) -> Vec<Graph> {
        let mut subgraphs = Vec::<Graph>::new();
        let mut unvisited = self.g.keys().map(|v| *v).
                                    collect::<HashSet<usize>>();
        while !unvisited.is_empty() {
            let v0 = unvisited.iter().next().unwrap();
            let mut g = HashMap::<usize, Vec<usize>>::new();
            let mut stack: Vec<usize> = vec![*v0];
            while !stack.is_empty() {
                let v = stack.pop().unwrap();
                let vs = self.g.get(&v).unwrap();
                let vs_copy = vs.iter().map(|v1| *v1).
                                        collect::<Vec<usize>>();
                g.insert(v, vs_copy);
                unvisited.remove(&v);
                for v1 in vs.iter() {
                    if unvisited.contains(v1) {
                        stack.push(*v1);
                        unvisited.remove(v1);
                    }
                }
            }
            subgraphs.push(Graph { g })
        }
        subgraphs
    }
}


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

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

fn create_graph(cells: Vec<Point>) -> Graph {
    let m = cells.iter().zip(0..).map(|(pt, i)| (*pt, i)).
                        collect::<HashMap<Point, usize>>();
    let dirs = vec![(-1, -1), (-1, 0), (0, -1), (0, 1), (1, 0), (1, 1)].
                iter().map(|&(x, y)| Point { x, y }).collect::<Vec<Point>>();
    let neighbors = |&pt| -> Vec<usize> {
        dirs.iter().map(|&dir| pt + dir).filter(|nei| m.contains_key(nei)).
                    map(|nei| *m.get(&nei).unwrap()).collect::<Vec<usize>>()
    };
    let g: HashMap<usize, Vec<usize>> = cells.iter().enumerate().
                            map(|(i, pt)| (i, neighbors(pt))).collect();
    Graph { g }
}

fn f(cells: Vec<Point>) -> usize {
    let graph = create_graph(cells);
    graph.divide_into_connected().len()
}

fn main() {
    let cells = read_input();
    println!("{}", f(cells))
}