Submission #35152746
Source Code Expand
use proconio::input;
fn main() {
input! {
t: usize,
case: [(usize, usize, usize, usize, usize); t]
}
for (p, a, b, s, g) in case {
if a == 0 {
if s == g {
println!("0");
} else if b == g {
println!("1");
} else {
println!("-1");
}
} else {
// f(x) = (ax+b) % p
// fm(x) = (a^mx + a^(m-1)b + ... + b) % p = (a^mx + b * (a^m-1) / (a-1)) % p
let m = sqrt(p);
let a_inv = mod_div(1, a, p);
let f_inv = |y: usize| {
(y + p - b) * a_inv % p
};
let result = if a == 1 {
let f_m = |x: usize| {
(x + m * b) % p
};
baby_step_giant_step(s, g, p, m, f_m, f_inv)
} else {
let a_pow_m = mod_pow(a, m, p);
let a_minus_1_inv = mod_div(1, a-1, p);
let f_m = |x: usize| {
(a_pow_m * x + b * ((a_pow_m-1) * a_minus_1_inv % p)) % p
};
baby_step_giant_step(s, g, p, m, f_m, f_inv)
};
match result {
Some(result) => {
println!("{}", result);
}
None => {
println!("-1");
}
}
}
}
}
/// xからyにするにはfを何回適用すればいいか求める
/// # Arguments
///
/// * `x` - 開始状態
/// * `y` - 終了状態
/// * `max` - `f`を適用する回数の上限
/// * `m`, `f_m` - `x`に`f`を`m`回適用したときの状態
/// * `f_inv` - `f`の逆関数
///
/// # Returns
/// * `Some(n)` - `f^n(x)=y`であるような最小の`n`
/// * `None` - 'max`回以下では`x`を`y`にできない
///
fn baby_step_giant_step<T, FM, FINV>(x: T, y: T, max: usize, m: usize, f_m: FM, f_inv: FINV) -> Option<usize>
where
T: Copy + Eq + std::hash::Hash,
FM: Fn(T) -> T,
FINV: Fn(T) -> T
{
let mut result = None;
let mut candidates = std::collections::HashSet::new();
let mut candidate = y;
for _j in (0..m).rev() {
candidates.insert(candidate);
candidate = f_inv(candidate);
}
let mut f_im_x = x;
for i in 0..=max/m {
if candidates.contains(&f_im_x) {
let mut v = f_m(f_im_x);
for j in (0..m).rev() {
v = f_inv(v);
if v == y {
result = Some(i * m + j);
}
}
break;
}
f_im_x = f_m(f_im_x);
}
result
}
/// 平方根
///
/// # Arguments
///
/// * `n` - 対象の数
///
/// # Returns
///
/// n^0.5(小数点以下切り捨て)
///
pub fn sqrt(n: usize) -> usize {
if n == 0 {
0
} else {
b_search_find_last(1, n, |i| i <= n / i).unwrap()
}
}
pub fn mod_pow(n: usize, mut k: usize, p: usize) -> usize {
let mut val = n;
let mut result: usize = 1;
while k > 0 {
if k % 2 == 1 {
result = (result * val) % p;
}
val = (val * val) % p;
k /= 2;
}
result
}
pub fn mod_div(a: usize, b: usize, p: usize) -> usize {
a * mod_pow(b, p-2, p) % p
}
/// 二分探索
///
/// # Arguments
///
/// * `[left, right]`: 探索範囲
/// * `is_valid(i)` - iが有効かどうか
///
/// # Returns
/// * `Some(i)` - is_valid(i)がtrueになる最後のi
/// * `None` - is_valid(i)がすべてfalseになる場合
///
pub fn b_search_find_last<P>(left: usize, right: usize, is_valid: P) -> Option<usize> where
P: Fn(usize) -> bool
{
let mut min = left;
let mut max = right;
if min > max {
None
} else {
while min < max {
let c = max - (max - min) / 2;
if is_valid(c) {
min = c;
} else {
max = c - 1;
}
}
if is_valid(min) {
Some(min)
} else {
None
}
}
}
Submission Info
| Submission Time |
|
| Task |
G - Sequence in mod P |
| User |
Hirekatsu |
| Language |
Rust (1.42.0) |
| Score |
600 |
| Code Size |
3961 Byte |
| Status |
AC |
| Exec Time |
214 ms |
| Memory |
3128 KiB |
Judge Result
| Set Name |
Sample |
All |
| Score / Max Score |
0 / 0 |
600 / 600 |
| Status |
|
|
| Set Name |
Test Cases |
| Sample |
sample_01.txt |
| All |
random_01.txt, random_02.txt, random_03.txt, random_04.txt, random_05.txt, random_06.txt, random_07.txt, random_08.txt, random_09.txt, random_10.txt, random_11.txt, random_12.txt, random_13.txt, random_14.txt, random_15.txt, random_16.txt, random_17.txt, random_18.txt, random_19.txt, random_20.txt, random_21.txt, random_22.txt, random_23.txt, random_24.txt, random_25.txt, random_26.txt, sample_01.txt |
| Case Name |
Status |
Exec Time |
Memory |
| random_01.txt |
AC |
6 ms |
2124 KiB |
| random_02.txt |
AC |
2 ms |
2072 KiB |
| random_03.txt |
AC |
2 ms |
1984 KiB |
| random_04.txt |
AC |
2 ms |
2036 KiB |
| random_05.txt |
AC |
209 ms |
3004 KiB |
| random_06.txt |
AC |
180 ms |
2984 KiB |
| random_07.txt |
AC |
191 ms |
2968 KiB |
| random_08.txt |
AC |
176 ms |
2904 KiB |
| random_09.txt |
AC |
184 ms |
2964 KiB |
| random_10.txt |
AC |
193 ms |
3128 KiB |
| random_11.txt |
AC |
195 ms |
3024 KiB |
| random_12.txt |
AC |
190 ms |
2932 KiB |
| random_13.txt |
AC |
214 ms |
2956 KiB |
| random_14.txt |
AC |
199 ms |
2932 KiB |
| random_15.txt |
AC |
110 ms |
3104 KiB |
| random_16.txt |
AC |
89 ms |
2476 KiB |
| random_17.txt |
AC |
187 ms |
2932 KiB |
| random_18.txt |
AC |
203 ms |
3000 KiB |
| random_19.txt |
AC |
197 ms |
2908 KiB |
| random_20.txt |
AC |
197 ms |
3128 KiB |
| random_21.txt |
AC |
207 ms |
2932 KiB |
| random_22.txt |
AC |
192 ms |
2928 KiB |
| random_23.txt |
AC |
209 ms |
3036 KiB |
| random_24.txt |
AC |
193 ms |
2892 KiB |
| random_25.txt |
AC |
201 ms |
2940 KiB |
| random_26.txt |
AC |
203 ms |
2968 KiB |
| sample_01.txt |
AC |
1 ms |
2064 KiB |