use super::functions::*;
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct IntExtContinuedFraction {
pub coeffs: Vec<i64>,
}
#[allow(dead_code)]
impl IntExtContinuedFraction {
pub fn from_ratio(mut p: i64, mut q: i64) -> Self {
let mut coeffs = Vec::new();
while q != 0 {
coeffs.push(p / q);
let r = p % q;
p = q;
q = r;
}
IntExtContinuedFraction { coeffs }
}
pub fn to_ratio(&self) -> (i64, i64) {
if self.coeffs.is_empty() {
return (0, 1);
}
let mut num = 1i64;
let mut den = 0i64;
for &a in self.coeffs.iter().rev() {
let new_num = a * num + den;
den = num;
num = new_num;
}
(num, den)
}
pub fn convergent(&self, n: usize) -> Option<(i64, i64)> {
if n >= self.coeffs.len() {
return None;
}
let sub = IntExtContinuedFraction {
coeffs: self.coeffs[..=n].to_vec(),
};
Some(sub.to_ratio())
}
pub fn depth(&self) -> usize {
self.coeffs.len()
}
}
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct IntExtGaussian {
pub re: i64,
pub im: i64,
}
#[allow(dead_code)]
impl IntExtGaussian {
pub fn new(re: i64, im: i64) -> Self {
IntExtGaussian { re, im }
}
pub fn zero() -> Self {
IntExtGaussian { re: 0, im: 0 }
}
pub fn one() -> Self {
IntExtGaussian { re: 1, im: 0 }
}
pub fn i_unit() -> Self {
IntExtGaussian { re: 0, im: 1 }
}
pub fn add(self, other: Self) -> Self {
IntExtGaussian {
re: self.re + other.re,
im: self.im + other.im,
}
}
pub fn mul(self, other: Self) -> Self {
IntExtGaussian {
re: self.re * other.re - self.im * other.im,
im: self.re * other.im + self.im * other.re,
}
}
pub fn conj(self) -> Self {
IntExtGaussian {
re: self.re,
im: -self.im,
}
}
pub fn norm(self) -> i64 {
self.re * self.re + self.im * self.im
}
pub fn units() -> [Self; 4] {
[
IntExtGaussian::one(),
IntExtGaussian::new(-1, 0),
IntExtGaussian::i_unit(),
IntExtGaussian::new(0, -1),
]
}
pub fn is_unit(self) -> bool {
self.norm() == 1
}
pub fn divides(self, other: Self) -> bool {
if self.norm() == 0 {
return other.re == 0 && other.im == 0;
}
let n = self.norm();
let prod = other.mul(self.conj());
prod.re % n == 0 && prod.im % n == 0
}
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IntExtPadicVal {
pub prime: i64,
}
#[allow(dead_code)]
impl IntExtPadicVal {
pub fn new(prime: i64) -> Self {
IntExtPadicVal { prime }
}
pub fn val(&self, n: i64) -> Option<u32> {
if n == 0 || self.prime <= 1 {
return None;
}
let mut count = 0u32;
let mut current = n.abs();
while current % self.prime == 0 {
count += 1;
current /= self.prime;
}
Some(count)
}
pub fn power(&self, k: u32) -> i64 {
self.prime.pow(k)
}
pub fn divides_to_val(&self, a: i64, b: i64) -> bool {
match (self.val(a), self.val(b)) {
(Some(va), Some(vb)) => va >= vb,
(None, _) => false,
(_, None) => true,
}
}
pub fn unit_part(&self, n: i64) -> Option<i64> {
let v = self.val(n)?;
Some(n / self.power(v))
}
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IntExtEuclidResult {
pub gcd: i64,
pub x: i64,
pub y: i64,
}
#[allow(dead_code)]
impl IntExtEuclidResult {
pub fn compute(a: i64, b: i64) -> Self {
fn extended_gcd(a: i64, b: i64) -> (i64, i64, i64) {
if b == 0 {
(a.abs(), if a >= 0 { 1 } else { -1 }, 0)
} else {
let (g, x1, y1) = extended_gcd(b, a % b);
(g, y1, x1 - (a / b) * y1)
}
}
let (gcd, x, y) = extended_gcd(a, b);
IntExtEuclidResult { gcd, x, y }
}
pub fn verify(&self, a: i64, b: i64) -> bool {
a * self.x + b * self.y == self.gcd
}
pub fn is_coprime(&self) -> bool {
self.gcd == 1
}
pub fn modular_inverse(&self, _a: i64, b: i64) -> Option<i64> {
if self.gcd != 1 {
return None;
}
let inv = self.x % b;
Some(if inv < 0 { inv + b } else { inv })
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct IntCrtSolver {
congruences: Vec<(i64, i64)>,
}
#[allow(dead_code)]
impl IntCrtSolver {
pub fn new() -> Self {
IntCrtSolver {
congruences: Vec::new(),
}
}
pub fn add_congruence(&mut self, remainder: i64, modulus: i64) {
self.congruences.push((remainder, modulus));
}
pub fn solve(&self) -> Option<(i64, i64)> {
if self.congruences.is_empty() {
return Some((0, 1));
}
let (mut x, mut m) = self.congruences[0];
x = ((x % m) + m) % m;
for &(r, mi) in &self.congruences[1..] {
let ext = IntExtEuclidResult::compute(m, mi);
if ext.gcd != 1 {
return None;
}
let diff = r - x;
let new_m = m * mi;
let step = (diff % mi * ext.x % mi + mi) % mi;
x = ((x + m * step) % new_m + new_m) % new_m;
m = new_m;
}
Some((x, m))
}
pub fn len(&self) -> usize {
self.congruences.len()
}
pub fn is_empty(&self) -> bool {
self.congruences.is_empty()
}
}
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct IntExtSternBrocot {
pub p: i64,
pub q: i64,
}
#[allow(dead_code)]
impl IntExtSternBrocot {
pub fn root() -> Self {
IntExtSternBrocot { p: 1, q: 1 }
}
pub fn left_child(self) -> Self {
IntExtSternBrocot {
p: self.p,
q: self.p + self.q,
}
}
pub fn right_child(self) -> Self {
IntExtSternBrocot {
p: self.p + self.q,
q: self.q,
}
}
pub fn mediant(self, other: Self) -> Self {
IntExtSternBrocot {
p: self.p + other.p,
q: self.q + other.q,
}
}
pub fn approximate(target_num: i64, target_den: i64, steps: usize) -> Self {
let mut lo_p = 0i64;
let mut lo_q = 1i64;
let mut hi_p = 1i64;
let mut hi_q = 0i64;
let mut current = IntExtSternBrocot { p: 1, q: 1 };
for _ in 0..steps {
if current.p * target_den < target_num * current.q {
lo_p = current.p;
lo_q = current.q;
} else if current.p * target_den > target_num * current.q {
hi_p = current.p;
hi_q = current.q;
} else {
break;
}
current = IntExtSternBrocot {
p: lo_p + hi_p,
q: lo_q + hi_q,
};
}
current
}
pub fn to_f64(self) -> f64 {
self.p as f64 / self.q as f64
}
}