結果

問題 No.3396 ChRisTmas memory
コンテスト
ユーザー rsk0315
提出日時 2025-12-07 15:28:46
言語 Rust
(1.83.0 + proconio)
結果
AC  
実行時間 1,500 ms / 4,000 ms
コード長 6,886 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 22,999 ms
コンパイル使用メモリ 402,212 KB
実行使用メモリ 7,852 KB
最終ジャッジ日時 2025-12-07 15:29:27
合計ジャッジ時間 29,002 ms
ジャッジサーバーID
(参考情報)
judge3 / judge4
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 2
other AC * 40
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

use std::io::BufRead;

use nekolib::math::{Gcd, GcdRecip};
use proconio::{
    fastout, input,
    source::{Readable, Source},
};

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum Query {
    Q1(u64, u64),
    Q2(usize),
    Q3(u64),
}
use Query::*;

impl Readable for Query {
    type Output = Query;
    fn read<R: BufRead, S: Source<R>>(source: &mut S) -> Self::Output {
        match u32::read(source) {
            1 => {
                input! {
                    from source,
                    m: u64,
                    r: u64,
                }
                Q1(m, r)
            }
            2 => {
                input! {
                    from source,
                    k: usize,
                }
                Q2(k)
            }
            3 => {
                input! {
                    from source,
                    m: u64,
                }
                Q3(m)
            }
            _ => unreachable!(),
        }
    }
}

#[fastout]
fn main() {
    input! {
        query: [Query],
    }

    let mut a = vec![(0, 1, true)];
    for &q in &query {
        match q {
            Q1(m, r) => {
                let new = || {
                    let lj = a.iter().map(|&(_, mj, _)| mj).fold(1, |x, y| x * y % m);
                    let g = lj.gcd(m);
                    let mi = m / g;

                    let (si, _) = a.iter().fold((0, 1), |(sj, lj), (yj, mj, _)| ((sj + yj * lj) % m, lj * mj % m));

                    let num = r + m * g - si;
                    (num % g == 0).then(|| (num / g * (lj / g).gcd_recip(mi).1 % mi, mi))
                };

                if let Some((yi, mi)) = new() {
                    a.push((yi, mi, true));
                } else {
                    a.push((0, 0, false));
                }
            }
            Q2(k) => {
                for _ in 0..k {
                    a.pop();
                }
            }
            Q3(m) => {
                if let Some((res, _)) =
                    a.iter().try_fold((0, 1), |(sj, lj), (yj, mj, ok)| ok.then(|| ((sj + yj * lj) % m, lj * mj % m)))
                {
                    println!("{res}");
                } else {
                    println!("-1");
                }
            }
        }
    }
}

/// This module is bundled automatically.
/// See <https://rsk0315.github.io/nekolib/nekolib_doc/index.html> for documentation.
/// Commit: f384433ce1b82eac51a72c3142b4d046158d1e1d-dirty
#[allow(unused)]
#[allow(private_interfaces)]
pub mod nekolib {
    pub mod math {
        pub mod gcd {
            pub trait Gcd {
                fn gcd(self, other: Self) -> Self;
            }
            macro_rules! impl_uint {
                            ( $($ty:ty)* ) => { $(
                                impl Gcd for $ty {
                                    fn gcd(mut self, mut other: Self) -> Self {
                                        while other != 0 {
                                            let tmp = self % other;
                                            self = std::mem::replace(&mut other, tmp);
                                        }
                                        self
                                    }
                                }
                            )* }
                        }
            impl_uint! { u8 u16 u32 u64 u128 usize }
        }
        #[allow(unused_imports)]
        pub use gcd::*;
        pub mod gcd_recip {
            pub trait GcdRecip: Sized {
                fn gcd_recip(self, other: Self) -> (Self, Self);
            }
            macro_rules! impl_uint {
                            ($t:ty) => {
                                impl GcdRecip for $t {
                                    fn gcd_recip(self, other: Self) -> (Self, Self) {
                                        assert!(other > 0);
                                        let a = self % other;
                                        if a == 0 {
                                            return (other, 0);
                                        }

                                        let mut s = other;
                                        let mut t = a;
                                        let mut m0 = 0;
                                        let mut m1 = 1;
                                        while t > 0 {
                                            let u = s / t;
                                            s -= t * u;
                                            // m0 -= m1 * u;
                                            let v = (m1 * u) % other;
                                            m0 = if m0 < v { m0 + other - v } else { m0 - v };
                                            std::mem::swap(&mut s, &mut t);
                                            std::mem::swap(&mut m0, &mut m1);
                                        }
                                        (s, m0 % (other / s))
                                    }
                                }
                            };
                            ( $($t:ty)* ) => { $(impl_uint!($t);)* };
                        }
            macro_rules! impl_int {
                            ($t:ty) => {
                                impl GcdRecip for $t {
                                    fn gcd_recip(self, other: Self) -> (Self, Self) {
                                        assert!(other > 0);
                                        let a = self.rem_euclid(other);
                                        if a == 0 {
                                            return (other, 0);
                                        }

                                        let mut s = other;
                                        let mut t = a;
                                        let mut m0 = 0;
                                        let mut m1 = 1;
                                        while t > 0 {
                                            let u = s / t;
                                            s -= t * u;
                                            m0 -= m1 * u;
                                            std::mem::swap(&mut s, &mut t);
                                            std::mem::swap(&mut m0, &mut m1);
                                        }
                                        if m0 < 0 {
                                            m0 += other / s;
                                        }
                                        (s, m0)
                                    }
                                }
                            };
                            ( $($t:ty)* ) => { $(impl_int!($t);)* };
                        }
            impl_uint!(u8 u16 u32 u64 u128 usize);
            impl_int!(i8 i16 i32 i64 i128 isize);
        }
        #[allow(unused_imports)]
        pub use gcd_recip::*;
    }
}
0