complete 3586.rs
This commit is contained in:
418
storage/zeta/rs/completed/3586.rs
Normal file
418
storage/zeta/rs/completed/3586.rs
Normal file
@@ -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<Expr>,
|
||||
right: Box<Expr>,
|
||||
},
|
||||
}
|
||||
|
||||
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<Expr> = vec![];
|
||||
|
||||
let mut signal = SolutionSignal::Undef;
|
||||
|
||||
ops.iter().for_each(|&x| match x.parse::<u64>() {
|
||||
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::<Vec<&str>>();
|
||||
|
||||
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"),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user