https://atcoder.jp/contests/abc421/tasks/abc421_d
RLEが2人で違いますが、分割して同期を取ると簡単になります。
Generic版のPointを今までより強化しました。
// RLE Moving #![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() } //////////////////// Point //////////////////// use std::ops::{Add, Sub, Mul, Neg}; #[derive(Copy, Clone, PartialEq)] struct Point<T> { x: T, y: T, } impl<T> Point<T> { fn new(x: T, y: T) -> Self { Self { x, y } } } impl<T> Add<Point<T>> for Point<T> where T: Add<Output = T> + Copy, { type Output = Point<T>; fn add(self, other: Self) -> Self::Output { Self::new(self.x + other.x, self.y + other.y) } } impl<T> Sub<Point<T>> for Point<T> where T: Sub<Output = T> + Copy, { type Output = Point<T>; fn sub(self, other: Self) -> Self::Output { Self::new(self.x - other.x, self.y - other.y) } } // Point<T> * T impl<T> Mul<T> for Point<T> where T: Mul<Output = T> + Copy, { type Output = Point<T>; fn mul(self, other: T) -> Self::Output { Self::new(self.x * other, self.y * other) } } // Point<T> * T impl<T> Neg for Point<T> where T: Neg<Output = T> + Copy, { type Output = Point<T>; fn neg(self) -> Self::Output { Self::new(-self.x, -self.y) } } //////////////////// process //////////////////// type RLE = (Point<i64>, i64); fn read_RLE() -> RLE { let v: Vec<String> = read_vec(); let A: i64 = v[1].parse().ok().unwrap(); match v[0].as_str() { "U" => (Point::new(-1, 0), A), "D" => (Point::new( 1, 0), A), "L" => (Point::new( 0, -1), A), _ => (Point::new( 0, 1), A) } } fn read_input() -> (Point<i64>, Point<i64>, Vec<RLE>, Vec<RLE>) { let v: Vec<i64> = read_vec(); let Pt0 = Point::new(v[0], v[1]); let Pa0 = Point::new(v[2], v[3]); let w: Vec<usize> = read_vec(); let (M, L) = (w[1], w[2]); let RLEt: Vec<RLE> = (0..M).map(|_| read_RLE()).collect(); let RLEa: Vec<RLE> = (0..L).map(|_| read_RLE()).collect(); (Pt0, Pa0, RLEt, RLEa) } use std::cmp::{min, max}; fn integrate(rles1: Vec<RLE>, rles2: Vec<RLE>) -> Vec<(Point<i64>, Point<i64>, i64)> { let mut v: Vec<(Point<i64>, Point<i64>, i64)> = vec![]; let mut k: usize = 0; let mut l: usize = 0; let L1 = rles1.len(); let L2 = rles2.len(); let mut acc1: i64 = 0; let mut acc2: i64 = 0; while k < L1 && l < L2 { let (dir1, n1) = rles1[k]; let (dir2, n2) = rles2[l]; if acc1 + n1 == acc2 + n2 { let m = min(n1, n2); v.push((dir1, dir2, m)); k += 1; l += 1; acc1 += n1; acc2 += n2 } else if acc1 + n1 > acc2 + n2 { v.push((dir1, dir2, acc2 + n2 - max(acc1, acc2))); l += 1; acc2 += n2 } else { v.push((dir1, dir2, acc1 + n1 - max(acc1, acc2))); k += 1; acc1 += n1 } } v } fn collides(pt1: Point<i64>, pt2: Point<i64>, dir1: Point<i64>, dir2: Point<i64>, n: i64) -> bool { let v = pt1 - pt2; let d = dir2 - dir1; if dir1 == dir2 || v.x * d.y != v.y * d.x { false } else { if v.x != 0 { if v.x % d.x != 0 { false } else { let m = v.x / d.x; 0 < m && m <= n } } else { if v.y % d.y != 0 { false } else { let m = v.y / d.y; 0 < m && m <= n } } } } fn num_crosses(pt1: Point<i64>, pt2: Point<i64>, dir1: Point<i64>, dir2: Point<i64>, n: i64) -> i64 { if pt1 == pt2 { if dir1 == dir2 { n } else { 0 } } else { if collides(pt1, pt2, dir1, dir2, n) { 1 } else { 0 } } } fn F(Pt0: Point<i64>, Pa0: Point<i64>, RLEt: Vec<RLE>, RLEa: Vec<RLE>) -> i64 { let v = integrate(RLEt, RLEa); let mut counter: i64 = 0; let mut pt1 = Pt0; let mut pt2 = Pa0; for (dir1, dir2, n) in v { counter += num_crosses(pt1, pt2, dir1, dir2, n); pt1 = pt1 + dir1 * n; pt2 = pt2 + dir2 * n; } counter } fn main() { let (Pt0, Pa0, RLEt, RLEa) = read_input(); println!("{}", F(Pt0, Pa0, RLEt, RLEa)) }