結果

問題 No.981 一般冪乗根
ユーザー Haar
提出日時 2026-07-13 19:39:04
言語 Rust
(1.94.0 + proconio + num + itertools)
コンパイル:
/usr/bin/rustc_custom
実行:
./target/release/main
結果
AC  
実行時間 1,590 ms / 6,000 ms
+ 806µs
コード長 22,004 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 15,735 ms
コンパイル使用メモリ 226,992 KB
実行使用メモリ 9,312 KB
最終ジャッジ日時 2026-07-13 19:40:16
合計ジャッジ時間 51,215 ms
ジャッジサーバーID
(参考情報)
judge3_0 / judge1_0
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 30 RE * 14
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

// Bundled at 2026/07/13 19:37:14 +09:00
// Author: Haar

pub mod main {
    use super::*;
    #[allow(unused_imports)]
    use haar_lib::{get, input, io::fastio::*, iter::join_str::*, output};
    #[allow(unused_imports)]
    use std::cell::{Cell, RefCell};
    #[allow(unused_imports)]
    use std::cmp::{max, min, Reverse};
    #[allow(unused_imports)]
    use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};
    #[allow(unused_imports)]
    use std::io::Write;
    #[allow(unused_imports)]
    use std::mem::swap;
    #[allow(unused_imports)]
    use std::rc::Rc;
    pub struct Problem {
        io: FastIO,
    }
    use haar_lib::math::mod_ops::root::*;
    impl Problem {
        pub fn init() -> Self {
            Self { io: FastIO::new() }
        }
        pub fn main(&mut self) {
            let t = self.io.read_usize();
            for _ in 0..t {
                let p = self.io.read_u64();
                let k = self.io.read_u64();
                let a = self.io.read_u64();
                let ans = mod_kth_root(a, k, p);
                if let Some(ans) = ans {
                    self.io.writeln(ans);
                } else {
                    self.io.writeln(-1);
                }
            }
        }
    }
}
fn main() {
    std::thread::Builder::new()
        .spawn(|| main::Problem::init().main())
        .unwrap()
        .join()
        .unwrap()
}
use crate as haar_lib;
pub mod io {
    pub mod fastio {
        use std::fmt::Display;
        use std::io::{Read, Write};
        pub struct FastIO {
            in_bytes: Vec<u8>,
            in_cur: usize,
            out_buf: std::io::BufWriter<std::io::Stdout>,
        }
        impl FastIO {
            pub fn new() -> Self {
                let mut s = vec![];
                std::io::stdin().read_to_end(&mut s).unwrap();
                let cout = std::io::stdout();
                Self {
                    in_bytes: s,
                    in_cur: 0,
                    out_buf: std::io::BufWriter::new(cout),
                }
            }
            #[inline]
            pub fn getc(&mut self) -> Option<u8> {
                let c = *self.in_bytes.get(self.in_cur)?;
                self.in_cur += 1;
                Some(c)
            }
            #[inline]
            pub fn peek(&self) -> Option<u8> {
                Some(*self.in_bytes.get(self.in_cur)?)
            }
            #[inline]
            pub fn skip(&mut self) {
                while self.peek().is_some_and(|c| c.is_ascii_whitespace()) {
                    self.in_cur += 1;
                }
            }
            pub fn read_u64(&mut self) -> u64 {
                self.skip();
                let mut ret: u64 = 0;
                while self.peek().is_some_and(|c| c.is_ascii_digit()) {
                    ret = ret * 10 + (self.in_bytes[self.in_cur] - b'0') as u64;
                    self.in_cur += 1;
                }
                ret
            }
            pub fn read_u32(&mut self) -> u32 {
                self.read_u64() as u32
            }
            pub fn read_usize(&mut self) -> usize {
                self.read_u64() as usize
            }
            pub fn read_i64(&mut self) -> i64 {
                self.skip();
                let mut ret: i64 = 0;
                let minus = if self.peek() == Some(b'-') {
                    self.in_cur += 1;
                    true
                } else {
                    false
                };
                while self.peek().is_some_and(|c| c.is_ascii_digit()) {
                    ret = ret * 10 + (self.in_bytes[self.in_cur] - b'0') as i64;
                    self.in_cur += 1;
                }
                if minus {
                    ret = -ret;
                }
                ret
            }
            pub fn read_i32(&mut self) -> i32 {
                self.read_i64() as i32
            }
            pub fn read_isize(&mut self) -> isize {
                self.read_i64() as isize
            }
            pub fn read_f64(&mut self) -> f64 {
                self.read_chars()
                    .into_iter()
                    .collect::<String>()
                    .parse()
                    .unwrap()
            }
            pub fn read_chars(&mut self) -> Vec<char> {
                self.read_bytes().into_iter().map(Into::into).collect()
            }
            pub fn read_string(&mut self) -> String {
                self.read_chars().into_iter().collect()
            }
            pub fn read_bytes(&mut self) -> Vec<u8> {
                self.skip();
                let mut ret = vec![];
                while self.peek().is_some_and(|c| c.is_ascii_graphic()) {
                    ret.push(self.in_bytes[self.in_cur]);
                    self.in_cur += 1;
                }
                ret
            }
            pub fn read_char(&mut self) -> char {
                self.skip();
                self.getc().unwrap().into()
            }
            pub fn writeln_u32(&mut self, mut n: u32) {
                if n == 0 {
                    self.out_buf.write_all(b"0\n").unwrap();
                    return;
                }
                let mut buf = [b' '; 10];
                let mut i = 9;
                while n > 0 {
                    buf[i] = (n % 10) as u8 + b'0';
                    n /= 10;
                    i -= 1;
                }
                self.out_buf.write_all(&buf).unwrap();
                self.out_buf.write_all(b"\n").unwrap();
            }
            pub fn write<T: Display>(&mut self, s: T) {
                self.out_buf.write_all(s.to_string().as_bytes()).unwrap();
            }
            pub fn write_rev<T: Display>(&mut self, s: T) {
                let mut s = s.to_string().as_bytes().to_vec();
                s.reverse();
                self.out_buf.write_all(&s).unwrap();
            }
            pub fn writeln<T: Display>(&mut self, s: T) {
                self.write(s);
                self.out_buf.write_all(b"\n").unwrap();
            }
            pub fn writeln_rev<T: Display>(&mut self, s: T) {
                self.write_rev(s);
                self.out_buf.write_all(b"\n").unwrap();
            }
            pub fn write_bytes(&mut self, s: &[u8]) {
                self.out_buf.write_all(s).unwrap();
            }
            pub fn writeln_intersperse<I>(&mut self, it: I)
            where
                I: IntoIterator,
                I::Item: Display,
            {
                let mut it = it.into_iter();
                if let Some(s) = it.next() {
                    self.write(s);
                }
                for s in it {
                    self.write_bytes(b" ");
                    self.write(s);
                }
                self.write_bytes(b"\n");
            }
        }
        impl Drop for FastIO {
            fn drop(&mut self) {
                self.out_buf.flush().unwrap();
            }
        }
    }
}
pub mod iter {
    pub mod join_str {
        pub trait JoinStr: Iterator {
            fn join_str(self, s: &str) -> String
            where
                Self: Sized,
                Self::Item: ToString,
            {
                self.map(|x| x.to_string()).collect::<Vec<_>>().join(s)
            }
        }
        impl<I> JoinStr for I where I: Iterator + ?Sized {}
    }
}
pub mod macros {
    pub mod io {
        #[macro_export]
        macro_rules! get {
    ( $in:expr; [$a:tt $(as $to:ty)*; $num:expr] ) => {
        (0..$num).map(|_| get!($in; $a $(as $to)*)).collect::<Vec<_>>()
    };
    ( $in:expr; ($($type:tt $(as $to:ty)*),*) ) => {
        ($(get!($in; $type $(as $to)*)),*)
    };
    ( $in:expr; i8 ) => { $in.read_i64() as i8 };
    ( $in:expr; i16 ) => { $in.read_i64() as i16 };
    ( $in:expr; i32 ) => { $in.read_i64() as i32 };
    ( $in:expr; i64 ) => { $in.read_i64() };
    ( $in:expr; isize ) => { $in.read_i64() as isize };
    ( $in:expr; u8 ) => { $in.read_u64() as u8 };
    ( $in:expr; u16 ) => { $in.read_u64() as u16 };
    ( $in:expr; u32 ) => { $in.read_u64() as u32 };
    ( $in:expr; u64 ) => { $in.read_u64() };
    ( $in:expr; usize ) => { $in.read_u64() as usize };
    ( $in:expr; char) => { $in.read_char() };
    ( $in:expr; [u8]) => { $in.read_bytes() };
    ( $in:expr; [char] ) => { $in.read_chars() };
    ( $in:expr; String ) => { $in.read_string() };
    ( $in:expr; $from:tt as $to:ty ) => { <$to>::from(get!($in; $from)) };
}
        #[macro_export]
        macro_rules! input {
    ( @inner $in:expr, $name:pat, $type:tt ) => {
        let $name = get!($in; $type);
    };
    ( @inner $in:expr, $name:pat, $type:tt as $to:ty ) => {
        let $name = get!($in; $type as $to);
    };
    ( $in:expr; $( $names:pat = $type:tt $(as $to:ty)? ),* ) => {
        $(input!(@inner $in, $names, $type $(as $to)?);)*
    }
}
        #[macro_export]
        macro_rules! output {
    ( @one $io:expr, $a:expr ) => {
        $io.write($a);
    };
    ( $io:expr; $a:expr, $($rest:expr),* ) => {
        output!(@one $io, $a);
        $(
            $io.write(" ");
            $io.write($rest);
        )*
        $io.writeln("");
    };
}
    }
}
pub mod math {
    pub mod factorize {
        pub mod pollard_rho {
            use crate::math::{gcd_lcm::*, montgomery::*, primality::miller_rabin::*};
            fn find_factor(n: u64, a: u64) -> Option<u64> {
                assert!(n % 2 == 1);
                let mn = Montgomery::new(n);
                let f = |x| mn.add(mn.mul(x, x), Wrapped(a));
                let mut x = mn.wrap(a);
                let mut y = f(x);
                loop {
                    x = f(x);
                    y = f(f(y));
                    let x = mn.unwrap(x);
                    let y = mn.unwrap(y);
                    let d = x.abs_diff(y).gcd(n);
                    if d == 1 {
                        continue;
                    }
                    return (d < n).then_some(d);
                }
            }
            pub fn pollard_rho(mut n: u64) -> Vec<u64> {
                assert!(n > 0);
                if n == 1 {
                    return vec![];
                }
                let mut ret = vec![];
                while n % 2 == 0 {
                    ret.push(2);
                    n /= 2;
                }
                let mut remain = vec![n];
                while let Some(n) = remain.pop() {
                    if n == 1 {
                        continue;
                    }
                    if MillerRabin.is_prime(n) {
                        ret.push(n);
                        continue;
                    }
                    if let Some(p) = (1..).find_map(|a| find_factor(n, a)) {
                        remain.push(n / p);
                        remain.push(p);
                    }
                }
                ret.sort();
                ret
            }
        }
    }
    pub mod gcd_lcm {
        use std::mem::swap;
        pub trait GcdLcm {
            type Output;
            fn gcd(self, _: Self::Output) -> Self::Output;
            fn lcm(self, _: Self::Output) -> Self::Output;
            fn gcd_lcm(self, _: Self::Output) -> (Self::Output, Self::Output);
        }
        macro_rules! gcd_lcm_impl_all {
    ( $($t:ty),* ) => {
        $(
            impl GcdLcm for $t {
                type Output = $t;
                fn gcd(self, mut b: Self::Output) -> Self::Output {
                    let mut a = self;
                    if a < b {
                        swap(&mut a, &mut b);
                    }
                    if b == 0 {
                        return a;
                    }
                    b.gcd(a % b)
                }
                fn lcm(self, b: Self::Output) -> Self::Output {
                    self / self.gcd(b) * b
                }
                fn gcd_lcm(self, b: Self::Output) -> (Self::Output, Self::Output) {
                    let g = self.gcd(b);
                    (g, self / g * b)
                }
            }
        )*
    }
}
        gcd_lcm_impl_all!(i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize);
    }
    pub mod mod_ops {
        pub mod inv {
            use crate::math::gcd_lcm::GcdLcm;
            pub fn mod_inv(mut a: u64, m: u64) -> Option<u64> {
                assert!(
                    0 < m && m <= 0xFFFFFFFF,
                    "Violated 0 < m <= 0xFFFFFFFF (m = {m})"
                );
                if a >= m {
                    a %= m;
                }
                if a.gcd(m) != 1 {
                    return None;
                }
                let mut b = m;
                let mut u = 1;
                let mut v = 0;
                while b > 0 {
                    let t = a / b;
                    a -= t * b;
                    (a, b) = (b, a);
                    if u < t * v {
                        u += m - (t * v) % m;
                        if u >= m {
                            u -= m;
                        }
                    } else {
                        u -= t * v;
                    }
                    (u, v) = (v, u);
                }
                Some(u)
            }
        }
        pub mod log {
            use crate::math::{
                gcd_lcm::GcdLcm,
                mod_ops::{inv::*, pow::*},
            };
            use std::collections::HashMap;
            pub fn mod_log(a: u64, mut b: u64, mut m: u64) -> Option<u64> {
                assert!(
                    0 < m && m <= 0xFFFFFFFF,
                    "Violated 0 < m <= 0xFFFFFFFF (m = {m})"
                );
                if b >= m {
                    b %= m;
                }
                if b == 1 {
                    return Some(0);
                }
                let mut d = 0;
                loop {
                    let g = a.gcd(m);
                    if g != 1 {
                        if b % g != 0 {
                            return None;
                        }
                        d += 1;
                        m /= g;
                        b /= g;
                        b *= mod_inv(a / g, m).unwrap();
                        b %= m;
                        if b == 1 {
                            return Some(d);
                        }
                    } else {
                        break;
                    }
                }
                let sq = (m as f64).sqrt() as u64 + 1;
                let mut mp = HashMap::new();
                let mut t = 1 % m;
                for i in 0..sq {
                    mp.entry(t).or_insert(i);
                    t *= a;
                    t %= m;
                }
                let x = mod_pow(mod_inv(a, m).unwrap(), sq, m);
                let mut t = b % m;
                for i in 0..sq {
                    if let Some(k) = mp.get(&t) {
                        return Some(i * sq + k + d);
                    }
                    t *= x;
                    t %= m;
                }
                None
            }
        }
        pub mod pow {
            #[inline]
            pub const fn mod_pow(mut x: u64, mut p: u64, m: u64) -> u64 {
                assert!(0 < m && m <= 0xFFFFFFFF, "Violated 0 < m <= 0xFFFFFFFF");
                if x >= m {
                    x %= m;
                }
                let mut ret = 1;
                while p > 0 {
                    if (p & 1) != 0 {
                        ret = (ret * x) % m;
                    }
                    x = (x * x) % m;
                    p >>= 1;
                }
                ret
            }
        }
        pub mod root {
            use crate::math::{
                gcd_lcm::GcdLcm,
                mod_ops::{inv::mod_inv, log::mod_log, pow::mod_pow},
                primitive_root_u64::primitive_root_u64,
            };
            pub fn mod_kth_root(a: u64, k: u64, p: u64) -> Option<u64> {
                let g = primitive_root_u64(p);
                let y = mod_log(g, a, p)?;
                let yg = y.gcd(p - 1);
                let kg = k.gcd(p - 1);
                if !yg.is_multiple_of(kg) {
                    return None;
                }
                let k_ = k / kg;
                let y_ = y / kg;
                let p_ = (p - 1) / kg;
                let z = y_ * mod_inv(k_, p_).unwrap() % p_;
                let x = mod_pow(g, z, p);
                assert_eq!(mod_pow(x, k, p), a % p);
                Some(x)
            }
        }
    }
    pub mod primality {
        pub mod miller_rabin {
            use crate::math::montgomery::*;
            pub use crate::math::primality::PrimalityTest;
            fn is_composite(a: u64, s: u32, d: u64, mg: Montgomery) -> bool {
                let a = mg.wrap(a);
                let pp = mg.wrap(mg.modulo() - 1);
                let mut x = mg.pow(a, d);
                if mg.unwrap(x) == 1 {
                    false
                } else {
                    for _ in 0..s {
                        if x == pp {
                            return false;
                        }
                        x = mg.mul(x, x);
                    }
                    true
                }
            }
            pub struct MillerRabin;
            impl PrimalityTest<u64> for MillerRabin {
                fn is_prime(&self, n: u64) -> bool {
                    if n <= 1 {
                        false
                    } else if n == 2 {
                        true
                    } else if n % 2 == 0 {
                        false
                    } else {
                        let s = (n - 1).trailing_zeros();
                        let d = (n - 1) >> s;
                        let mg = Montgomery::new(n);
                        if n < 4_759_123_141 {
                            ![2, 7, 61]
                                .into_iter()
                                .any(|a| a < n && is_composite(a, s, d, mg))
                        } else {
                            ![2, 325, 9375, 28178, 450775, 9780504, 1795265022]
                                .into_iter()
                                .any(|a| a < n && is_composite(a, s, d, mg))
                        }
                    }
                }
            }
        }
        pub trait PrimalityTest<T> {
            fn is_prime(&self, value: T) -> bool;
        }
    }
    pub mod primitive_root_u64 {
        use crate::math::{factorize::pollard_rho::*, montgomery::*, primality::miller_rabin::*};
        pub fn primitive_root_u64(p: u64) -> u64 {
            if p == 2 {
                return 1;
            }
            assert!(MillerRabin.is_prime(p), "{p} is not a prime number.");
            let pf = pollard_rho(p - 1);
            let mn = Montgomery::new(p);
            (2..p)
                .find(|&g| {
                    pf.iter()
                        .all(|f| mn.unwrap(mn.pow(mn.wrap(g), (p - 1) / f)) != 1)
                })
                .expect("No primitive roots.")
        }
    }
    pub mod montgomery {
        const B: u32 = 64;
        const R: u128 = 1 << B;
        const MASK: u128 = R - 1;
        #[derive(Clone, Copy)]
        pub struct Montgomery {
            modulo: u64,
            r2: u128,
            m: u64,
        }
        #[derive(Clone, Copy, PartialEq)]
        pub struct Wrapped(pub u64);
        impl Montgomery {
            pub fn new(modulo: u64) -> Self {
                assert!(modulo % 2 != 0);
                assert!(modulo > 0);
                let r = R % modulo as u128;
                let r2 = r * r % modulo as u128;
                let m = {
                    let mut ret: u64 = 0;
                    let mut r = R;
                    let mut i = 1;
                    let mut t = 0;
                    while r > 1 {
                        if t % 2 == 0 {
                            t += modulo;
                            ret += i;
                        }
                        t >>= 1;
                        r >>= 1;
                        i <<= 1;
                    }
                    ret
                };
                Self { modulo, r2, m }
            }
            pub fn modulo(&self) -> u64 {
                self.modulo
            }
            fn reduce(&self, value: u128) -> u64 {
                let &Self { modulo, m, .. } = self;
                let mut ret =
                    (((((value & MASK) * m as u128) & MASK) * modulo as u128 + value) >> B) as u64;
                if ret >= modulo {
                    ret -= modulo;
                }
                ret
            }
            pub fn wrap(&self, a: u64) -> Wrapped {
                Wrapped(self.reduce(a as u128 * self.r2))
            }
            pub fn unwrap(&self, a: Wrapped) -> u64 {
                self.reduce(a.0 as u128)
            }
            pub fn mul(&self, a: Wrapped, b: Wrapped) -> Wrapped {
                Wrapped(self.reduce(a.0 as u128 * b.0 as u128))
            }
            pub fn add(&self, a: Wrapped, b: Wrapped) -> Wrapped {
                let mut t = a.0 as u128 + b.0 as u128;
                if t > self.modulo as u128 {
                    t -= self.modulo as u128;
                }
                Wrapped(t as u64)
            }
            pub fn sub(&self, a: Wrapped, b: Wrapped) -> Wrapped {
                let mut t = a.0 as u128;
                if t < b.0 as u128 {
                    t += self.modulo as u128;
                }
                t -= b.0 as u128;
                Wrapped(t as u64)
            }
            pub fn pow(&self, mut a: Wrapped, mut p: u64) -> Wrapped {
                let mut ret = self.wrap(1);
                while p > 0 {
                    if (p & 1) != 0 {
                        ret = self.mul(ret, a);
                    }
                    a = self.mul(a, a);
                    p >>= 1;
                }
                ret
            }
        }
    }
}
0