From dd5e70e74ecb9f3f0c907c1b913a7ea89551c37b Mon Sep 17 00:00:00 2001 From: yenru0 Date: Wed, 12 Nov 2025 17:01:17 +0900 Subject: [PATCH] complete 3586.rs --- storage/zeta/rs/completed/3586.rs | 418 ++++++++++++++++++++++++++++++ 1 file changed, 418 insertions(+) create mode 100644 storage/zeta/rs/completed/3586.rs diff --git a/storage/zeta/rs/completed/3586.rs b/storage/zeta/rs/completed/3586.rs new file mode 100644 index 0000000..2be3147 --- /dev/null +++ b/storage/zeta/rs/completed/3586.rs @@ -0,0 +1,418 @@ +use core::panic; +use std::{ + io::stdin, + ops::{Add, Div, Mul, Neg, Sub}, +}; + +fn gcd(mut a: u64, mut b: u64) -> u64 { + while b != 0 { + let tmp = b; + b = a % b; + a = tmp; + } + a +} + +fn lcm(a: u64, b: u64) -> u64 { + if a == 0 && b == 0 { + return 0; + } + let cd = gcd(a, b); + + (a / cd) * b +} + +pub struct Rational { + sign: bool, + p: u64, + q: u64, +} + +impl Add for Rational { + type Output = Rational; + + fn add(self, other: Rational) -> Rational { + let (res_sign, res_p, res_q) = + add_rational_component(self.sign, self.p, self.q, other.sign, other.p, other.q); + Rational { + sign: res_sign, + p: res_p, + q: res_q, + } + } +} + +impl Sub for Rational { + type Output = Rational; + + fn sub(self, other: Rational) -> Rational { + let (res_sign, res_p, res_q) = + sub_rational_component(self.sign, self.p, self.q, other.sign, other.p, other.q); + Rational { + sign: res_sign, + p: res_p, + q: res_q, + } + } +} + +impl Mul for Rational { + type Output = Rational; + + fn mul(self, other: Rational) -> Rational { + let (res_sign, res_p, res_q) = + mul_rational_component(self.sign, self.p, self.q, other.sign, other.p, other.q); + Rational { + sign: res_sign, + p: res_p, + q: res_q, + } + } +} + +impl Div for Rational { + type Output = Rational; + + fn div(self, other: Rational) -> Rational { + let (res_sign, res_p, res_q) = + div_rational_component(self.sign, self.p, self.q, other.sign, other.p, other.q); + Rational { + sign: res_sign, + p: res_p, + q: res_q, + } + } +} + +impl Neg for Rational { + type Output = Rational; + + fn neg(self) -> Rational { + Rational { + sign: !self.sign, + p: self.p, + q: self.q, + } + } +} + +fn regular_rational_component(p: u64, q: u64) -> (u64, u64) { + let cd = gcd(p, q); + (p / cd, q / cd) +} + +fn add_rational_component( + sign_a: bool, + p_a: u64, + q_a: u64, + sign_b: bool, + p_b: u64, + q_b: u64, +) -> (bool, u64, u64) { + if p_a == 0 { + return (sign_b, p_b, q_b); + } + if p_b == 0 { + return (sign_a, p_a, q_a); + } + + let common_q = lcm(q_a, q_b); + + let val_a = (p_a) * (common_q / q_a); + let val_b = (p_b) * (common_q / q_b); + + let mut res_p: u64; + let mut res_q: u64 = common_q; + let res_sign: bool; + if sign_a == sign_b { + res_p = val_a + val_b; + res_sign = sign_a; + } else { + if val_a > val_b { + res_p = val_a - val_b; + res_sign = sign_a; + } else if val_b > val_a { + res_p = val_b - val_a; + res_sign = sign_b; + } else { + res_p = 0; + res_q = 1; + res_sign = false; + return (res_sign, res_p, res_q); + } + } + + (res_p, res_q) = regular_rational_component(res_p, res_q); + (res_sign, res_p, res_q) +} + +fn sub_rational_component( + /* a - b */ + sign_a: bool, + p_a: u64, + q_a: u64, + sign_b: bool, + p_b: u64, + q_b: u64, +) -> (bool, u64, u64) { + add_rational_component(sign_a, p_a, q_a, !sign_b, p_b, q_b) +} + +fn mul_rational_component( + sign_a: bool, + p_a: u64, + q_a: u64, + sign_b: bool, + p_b: u64, + q_b: u64, +) -> (bool, u64, u64) { + if p_a == 0 || p_b == 0 { + return (false, 0, 1); + } + + let res_sign = sign_a ^ sign_b; + + let mut res_p = p_a * p_b; + let mut res_q = q_a * q_b; + + (res_p, res_q) = regular_rational_component(res_p, res_q); + + (res_sign, res_p, res_q) +} + +fn div_rational_component( + /* a / b */ + sign_a: bool, + p_a: u64, + q_a: u64, + sign_b: bool, + p_b: u64, + q_b: u64, +) -> (bool, u64, u64) { + mul_rational_component(sign_a, p_a, q_a, sign_b, q_b, p_b) +} + +pub enum Operator { + Add, + Sub, + Mul, + Div, +} + +pub enum Expr { + Rational(Rational), + Var, + Op { + op: Operator, + left: Box, + right: Box, + }, +} + +pub enum SolutionSignal { + No, + Multiple, + Unique(Rational), + Undef, +} + +fn solve(ops: Vec<&str>) -> SolutionSignal { + let mut solution = Rational { + sign: false, + p: 0, + q: 1, + }; + + let mut stack: Vec = vec![]; + + let mut signal = SolutionSignal::Undef; + + ops.iter().for_each(|&x| match x.parse::() { + Ok(u) => { + stack.push(Expr::Rational(Rational { + sign: false, + p: u, + q: 1, + })); + } + Err(_) => match x.chars().next().unwrap() { + 'X' | 'x' => stack.push(Expr::Var), + '+' => { + let right: Expr = stack.pop().unwrap(); + let left: Expr = stack.pop().unwrap(); + match (left, right) { + (Expr::Rational(l_val), Expr::Rational(r_val)) => { + stack.push(Expr::Rational(l_val + r_val)) + } + (l, r) => stack.push(Expr::Op { + op: Operator::Add, + left: Box::new(l), + right: Box::new(r), + }), + } + } + '*' => { + let right: Expr = stack.pop().unwrap(); + let left: Expr = stack.pop().unwrap(); + match (left, right) { + (Expr::Rational(l_val), Expr::Rational(r_val)) => { + stack.push(Expr::Rational(l_val * r_val)) + } + (l, r) => stack.push(Expr::Op { + op: Operator::Mul, + left: Box::new(l), + right: Box::new(r), + }), + } + } + '/' => { + let right: Expr = stack.pop().unwrap(); + let left: Expr = stack.pop().unwrap(); + match (left, right) { + (Expr::Rational(l_val), Expr::Rational(r_val)) => { + stack.push(Expr::Rational(l_val / r_val)) + } + (l, r) => stack.push(Expr::Op { + op: Operator::Div, + left: Box::new(l), + right: Box::new(r), + }), + } + } + '-' => { + let right: Expr = stack.pop().unwrap(); + let left: Expr = stack.pop().unwrap(); + match (left, right) { + (Expr::Rational(l_val), Expr::Rational(r_val)) => { + stack.push(Expr::Rational(l_val - r_val)) + } + (l, r) => stack.push(Expr::Op { + op: Operator::Sub, + left: Box::new(l), + right: Box::new(r), + }), + } + } + _ => { + panic!("Invalid operator"); + } + }, + }); + + let mut root = stack.pop().unwrap(); + + if let Expr::Rational(r) = root { + if r.p == 0 { + signal = SolutionSignal::Multiple; + } else { + signal = SolutionSignal::No; + } + } else { + while let Expr::Op { op, left, right } = root { + match (*left, *right) { + (Expr::Rational(r), right_expr) => { + match op { + Operator::Add => { + solution = solution - r; + } + Operator::Sub => { + solution = -solution + r; + } + Operator::Mul => { + // a * f = s => f = s / a + if r.p == 0 { + // 0 * f = s + if (solution.p == 0) { + signal = SolutionSignal::Multiple; + } else { + signal = SolutionSignal::No; + } + break; + } else { + solution = solution / r; + } + } // a / (a / f) = 0 + Operator::Div => { + // a / f = s => f = a / s + if r.p == 0 && solution.p != 0 { + signal = SolutionSignal::No; + break; + } else if r.p == 0 && solution.p == 0 { + signal = SolutionSignal::Multiple; + break; + } else if r.p != 0 && solution.p == 0 { + signal = SolutionSignal::No; + break; + } else { + solution = r / solution; + } + } + } + root = right_expr; + } + (left_expr, Expr::Rational(r)) => { + // Right is Rational, move it to solution based on operator + match op { + Operator::Add => { + solution = solution - r; + } + Operator::Sub => { + solution = solution + r; + } + Operator::Mul => { + // f * a = s => f = s / a + if r.p == 0 { + // 0 * f = s + if (solution.p == 0) { + signal = SolutionSignal::Multiple; + } else { + signal = SolutionSignal::No; + } + break; + } else { + solution = solution / r; + } + } + Operator::Div => { + if r.p == 0 { + signal = SolutionSignal::No; + break; + } else { + // f / a = s => f = s * a + solution = solution * r; + } + } + } + root = left_expr; + } + _ => panic!("One side must be Rational"), + } + } + } + + return match signal { + SolutionSignal::No => SolutionSignal::No, + SolutionSignal::Multiple => SolutionSignal::Multiple, + SolutionSignal::Undef => SolutionSignal::Unique(solution), + SolutionSignal::Unique(_) => panic!("Unreachable"), + }; +} + +fn main() { + let mut line = String::new(); + stdin().read_line(&mut line).unwrap(); + let ops = line.split(' ').map(|x| x).collect::>(); + + match solve(ops) { + SolutionSignal::No => println!("NONE"), + SolutionSignal::Multiple => println!("MULTIPLE"), + SolutionSignal::Unique(rational) => { + print!("X = "); + if rational.sign { + print!("-"); + } + println!("{}/{}", rational.p, rational.q); + } + SolutionSignal::Undef => panic!("Unreachable"), + } +}