https://atcoder.jp/contests/abc398/tasks/abc398_d
風で煙を動かすのではなく、原点とRCを風と反対方向に動かします。
// Bonfire #![allow(non_snake_case)] use std::collections::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() } //////////////////// Point //////////////////// #[derive(Clone, Copy, Hash, Eq, PartialEq)] struct Point { x: i32, y: i32 } use std::ops::Sub; impl Sub for Point { type Output = Self; fn sub(self, other: Self) -> Self { let x = self.x - other.x; let y = self.y - other.y; Point { x, y } } } impl Point { fn new(x: i32, y: i32) -> Point { Point { x, y } } } //////////////////// process //////////////////// fn read_input() -> (Point, String) { let v: Vec<i32> = read_vec(); let RC = Point::new(v[1], v[2]); let S: String = read(); (RC, S) } fn dir(c: char) -> Point { match c { 'N' => Point::new(-1, 0), 'W' => Point::new(0, -1), 'S' => Point::new(1, 0), _ => Point::new(0, 1) } } fn F(RC: Point, S: String) -> String { let mut P0 = Point::new(0, 0); let mut P1 = RC; let mut bs: Vec<char> = vec![]; let mut smokes: HashSet<Point> = HashSet::new(); smokes.insert(P0); for c in S.chars() { let d = dir(c); P0 = P0 - d; P1 = P1 - d; smokes.insert(P0); bs.push(if smokes.contains(&P1) { '1' } else { '0' }) } bs.into_iter().collect::<String>() } fn main() { let (RC, S) = read_input(); println!("{}", F(RC, S)) }