1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
//! Chinese remaindering

use super::gcd_recip;

use gcd_recip::GcdRecip;

/// Chinese remaindering。
///
/// $\\gdef{\\lcm}{\\operatorname{lcm}}$
/// $(r\_0, m\_0)$ と $(r\_1, m\_1)$ に対し、以下を満たす $0\\le x\\lt\\lcm(m\_0, m\_1)$ を求める。
/// - $x\\bmod m\_0 = r\_0$
/// - $x\\bmod m\_1 = r\_1$
///
/// 中国剰余定理から、$\\gcd(m\_0, m\_1)=1$ であれば常に存在する。
/// そうでない場合、高々一つ存在する。
///
/// なお、計算の利便性のため、$\\lcm(m\_0, m\_1)$ も返す。以下の例も参照。
///
/// # Idea
/// $$ \\begin{aligned}
/// (y\\cdot m\_0+r\_0)\\bmod m\_1 &= r\_1 \\\\
/// (y\\cdot m\_0)\\bmod m\_1 &= (r\_1-r\_0)\\bmod m\_1 \\\\
/// \\end{aligned} $$
/// $g = \\gcd(m\_0, m\_1)$ として $(m\_0, m\_1) = (u\_0g, u\_1g)$ とすると、
/// $$ (y\\cdot u\_0g)\\bmod u\_1g = (r\_1-r\_0)\\bmod u\_1g. $$
/// 左辺は $g$ の倍数なので、右辺も $g$ の倍数となる必要がある。
/// よって、$r\_1\\not\\equiv r\_0\\pmod{g}$ であれば解なしとなる。
///
/// 以下、$r\_1\\equiv r\_0\\pmod{g}$ とする。このとき、$r\_1-r\_0$ は $g$ で割り切れ、
/// $$ \\begin{aligned}
/// (y\\cdot u\_0)\\bmod u\_1 &= \\left(\\frac{r\_1-r\_0}{g}\\right)\\bmod u\_1 \\\\
/// y &\\equiv \\left(\\frac{r\_1-r\_0}{g}\\right)\\cdot u\_0^{-1} \\pmod{u\_1}
/// \\end{aligned} $$
/// となる。$\\gcd(u\_0, u\_1)=1$ なので $u\_0^{-1}$ は存在する。
///
/// これを満たす $0\\le y\\lt u\_1$ は一意に定まり、$x = y\\cdot m\_0+r\_0$ を計算すればよい。
/// また、$u\_1 = m\_1/g$ より、$\\lcm(m\_0, m\_1) = m\_0\\cdot u\_1$ となる。
///
/// # Examples
/// ```
/// use nekolib::math::EquivMod;
///
/// assert_eq!((0_i64, 2).equiv_mod((1, 3)), Some((4, 6)));
/// assert_eq!((0_i64, 2).equiv_mod((1, 4)), None);
/// ```
///
/// イテレータと組み合わせてもよい。
/// 条件 $x\\bmod 1 = 0$ が単位元となることに注意。
/// ```
/// use nekolib::math::{EquivMod, Lcm};
///
/// let x = (2_i64..=20)
///     .map(|m| (m - 1, m))
///     .try_fold((0, 1), |x, y| x.equiv_mod(y));
///
/// let lcm = (2_i64..=20).fold(1, |x, y| x.lcm(y));
/// assert_eq!(x, Some((lcm - 1, lcm)));
/// ```
///
/// 簡略版もある。
/// ```
/// use nekolib::math::{EquivModIter, Lcm};
///
/// let x = (2_i64..=20).map(|m| (m - 1, m)).equiv_mod();
/// let lcm = (2_i64..=20).fold(1, |x, y| x.lcm(y));
/// assert_eq!(x, Some((lcm - 1, lcm)));
///
/// assert_eq!(std::iter::empty().equiv_mod(), Some((0_i32, 1)));
/// ```
///
///
/// # Reference
/// - <https://github.com/atcoder/ac-library/blob/master/atcoder/math.hpp>
///
/// ## See also
/// - <https://rsk0315.hatenablog.com/entry/2021/01/18/065720#crt>
pub trait EquivMod: Sized {
    fn equiv_mod(self, other: Self) -> Option<Self>;
}

macro_rules! impl_uint {
    ($t:ty) => {
        impl EquivMod for ($t, $t) {
            fn equiv_mod(self, other: Self) -> Option<Self> {
                let ((r0, m0), (r1, m1))
                    = if self.1 >= other.1 { (self, other) } else { (other, self) };
                if m0 % m1 == 0 {
                    return if r0 % m1 == r1 { Some((r0, m0)) } else { None }
                }
                let (g, re) = m0.gcd_recip(m1);
                let u1 = m1 / g;
                let (dr, neg) = if r1 >= r0 { (r1 - r0, false) } else { (r0 - r1, true) };
                if dr % g != 0 {
                    return None
                }
                let x = (if neg { u1 - dr / g % u1 } else { dr / g % u1 }) * re % u1;
                Some((r0 + x * m0, m0 * u1))
            }
        }
    };
    ( $($t:ty)* ) => { $(impl_uint!($t);)* };
}

macro_rules! impl_int {
    ($t:ty) => {
        impl EquivMod for ($t, $t) {
            fn equiv_mod(self, other: Self) -> Option<Self> {
                let ((r0, m0), (r1, m1))
                    = if self.1 >= other.1 { (self, other) } else { (other, self) };
                if m0 % m1 == 0 {
                    return if r0 % m1 == r1 { Some((r0, m0)) } else { None }
                }
                let (g, re) = m0.gcd_recip(m1);
                let u1 = m1 / g;
                if (r1 - r0) % g != 0 {
                    return None
                }
                let x = ((r1 - r0) / g).rem_euclid(u1) * re % u1;
                Some((r0 + x * m0, m0 * u1))
            }
        }
    };
    ( $($t:ty)* ) => { $(impl_int!($t);)* };
}

impl_uint!(u8 u16 u32 u64 u128 usize);
impl_int!(i8 i16 i32 i64 i128 isize);

#[test]
fn test_uint() {
    let m_max = 150_usize;
    for m0 in 1..=m_max {
        for m1 in 1..=m_max {
            let naive = {
                let mut res = vec![vec![None; m1]; m0];
                for x in (0..m0 * m1).rev() {
                    let r0 = x % m0;
                    let r1 = x % m1;
                    res[r0][r1] = Some(x);
                }
                res
            };
            for r0 in 0..m0 {
                for r1 in 0..m1 {
                    let x = (r0, m0).equiv_mod((r1, m1)).map(|x| x.0);
                    assert_eq!(x, naive[r0][r1]);
                }
            }
        }
    }
}

#[test]
fn test_int() {
    let m_max = 150_isize;
    for m0 in 1..=m_max {
        for m1 in 1..=m_max {
            let naive = {
                let mut res = vec![vec![None; m1 as usize]; m0 as usize];
                for x in (0..m0 * m1).rev() {
                    let r0 = (x % m0) as usize;
                    let r1 = (x % m1) as usize;
                    res[r0][r1] = Some(x);
                }
                res
            };
            for r0 in 0..m0 {
                for r1 in 0..m1 {
                    let x = (r0, m0).equiv_mod((r1, m1)).map(|x| x.0);
                    assert_eq!(x, naive[r0 as usize][r1 as usize]);
                }
            }
        }
    }
}

#[test]
fn test_iter() {
    let x = (2_i64..=20)
        .map(|m| (m - 1, m))
        .try_fold((0, 1), |x, y| x.equiv_mod(y));
    let y = 232792560;

    assert_eq!(x, Some((y - 1, y)));
}

/// Chinese remaindering。
///
/// [`EquivMod`] のイテレータ版。
pub trait EquivModIter<I: Sized> {
    fn equiv_mod(self) -> Option<(I, I)>;
}

macro_rules! impl_iter {
    ($t:ty) => {
        impl<I: Iterator<Item = ($t, $t)>> EquivModIter<$t> for I {
            fn equiv_mod(mut self) -> Option<($t, $t)> {
                self.try_fold((0, 1), |x, y| x.equiv_mod(y))
            }
        }
    };
    ( $($t:ty)* ) => { $(impl_iter!($t);)* };
}

impl_iter!(u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize);

#[test]
fn test_iter2() {
    let x = (2_i64..=20).map(|m| (m - 1, m)).equiv_mod();
    let y = 232792560;

    assert_eq!(x, Some((y - 1, y)));
}