結果
| 問題 |
No.950 行列累乗
|
| コンテスト | |
| ユーザー |
akakimidori
|
| 提出日時 | 2019-12-14 01:58:03 |
| 言語 | Rust (1.83.0 + proconio) |
| 結果 |
WA
|
| 実行時間 | - |
| コード長 | 4,446 bytes |
| コンパイル時間 | 14,872 ms |
| コンパイル使用メモリ | 378,504 KB |
| 実行使用メモリ | 5,376 KB |
| 最終ジャッジ日時 | 2024-06-28 01:07:42 |
| 合計ジャッジ時間 | 16,978 ms |
|
ジャッジサーバーID (参考情報) |
judge5 / judge3 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 2 RE * 2 |
| other | AC * 9 WA * 9 RE * 39 |
ソースコード
use std::io::Read;
fn mod_pow(r: u64, mut n: u64, p: u64) -> u64 {
assert!(r < p);
let mut t = 1;
let mut s = r;
while n > 0 {
if n & 1 == 1 {
t = t * s % p;
}
s = s * s % p;
n >>= 1;
}
t
}
fn inv(a: u64, p: u64) -> u64 {
assert!(0 < a && a < p);
mod_pow(a, p - 2, p)
}
fn log(x: u64, a: u64, p: u64) -> u64 {
assert!(0 < x && x < p && a < p);
let mut phi = p - 1;
let mut factor = vec![];
let mut k = 2;
while k * k <= phi {
if phi % k == 0 {
factor.push(k);
while phi % k == 0 {
phi /= k;
}
}
k += 1;
}
if phi > 1 {
factor.push(phi);
}
let mut phi = p - 1;
for &f in &factor {
while phi % f == 0 && mod_pow(x, phi / f, p) == 1 {
phi /= f;
}
}
let phi = phi;
let sq = (phi as f64).sqrt() as u64 + 1;
let mut map = std::collections::HashMap::new();
for i in (0..sq).rev() {
map.insert(a * mod_pow(inv(x, p), i, p), i);
}
let mut k = 1;
let x = mod_pow(x, sq, p);
let mut ans = p;
for i in 0..sq {
if let Some(&v) = map.get(&k) {
let v = (i * sq + v) % phi;
if v == 0 {
ans = std::cmp::min(ans, phi);
} else {
ans = std::cmp::min(ans, v);
}
}
k = k * x % p;
}
ans
}
type M = [[u64; 2]; 2];
fn matmul(a: &M, b: &M, p: u64) -> M {
let mut c = [[0; 2]; 2];
for (c, a) in c.iter_mut().zip(a.iter()) {
for (a, b) in a.iter().zip(b.iter()) {
for (c, b) in c.iter_mut().zip(b.iter()) {
*c = (*c + *a * *b) % p;
}
}
}
c
}
fn matmul_s(a: &M, x: u64, p: u64) -> M {
let mut c = [[0; 2]; 2];
for (c, a) in c.iter_mut().zip(a.iter()) {
for (c, a) in c.iter_mut().zip(a.iter()) {
*c = *a * x % p;
}
}
c
}
fn mat_pow(a: &M, mut n: u64, p: u64) -> M {
let mut t = [[0; 2]; 2];
t[0][0] = 1;
t[1][1] = 1;
let mut s = a.clone();
while n > 0 {
if n & 1 == 1 {
t = matmul(&t, &s, p);
}
s = matmul(&s, &s, p);
n >>= 1;
}
t
}
fn run() {
let mut s = String::new();
std::io::stdin().read_to_string(&mut s).unwrap();
let mut it = s.trim().split_whitespace();
let p: u64 = it.next().unwrap().parse().unwrap();
let mut a: M = [[0; 2]; 2];
let mut b: M = [[0; 2]; 2];
for i in 0..2 {
for j in 0..2 {
a[i][j] = it.next().unwrap().parse().unwrap();
}
}
for i in 0..2 {
for j in 0..2 {
b[i][j] = it.next().unwrap().parse().unwrap();
}
}
if a == b {
println!("1");
return;
}
let det = (a[0][0] * a[1][1] % p + p - a[0][1] * a[1][0] % p)% p;
if det == 0 {
let x = (a[0][0] + a[1][1]) % p;
if x == 0 {
if b == [[0; 2]; 2] {
println!("2");
} else {
println!("-1");
}
return;
}
let mut y = p;
for i in 0..2 {
for j in 0..2 {
if a[i][j] != 0 {
y = std::cmp::min(y, log(x, a[i][j], p));
}
}
}
if y < p && b == matmul_s(&a, y, p) {
println!("{}", y);
} else {
println!("-1");
}
} else {
assert!(false);
let idet = inv(det, p);
let ia = matmul_s(&[[a[1][1], (p - a[0][1]) % p], [(p - a[1][0]) % p, a[0][0]]], idet, p);
assert!(matmul(&a, &ia, p) == [[1, 0], [0, 1]]);
let sq = 2_000_000;
let mut map = std::collections::HashMap::new();
let mut v = matmul(&b, &mat_pow(&ia, sq - 1, p), p);
for i in (0..sq).rev() {
map.insert(v, i);
v = matmul(&v, &a, p);
}
let mut k = [[1, 0], [0, 1]];
let x = mat_pow(&a, sq, p);
let mut ans = sq * sq;
for i in 0..sq {
if let Some(&v) = map.get(&k) {
ans = std::cmp::min(ans, sq * i + v);
}
k = matmul(&k, &x, p);
}
if ans < sq * sq {
println!("{}", ans);
} else {
assert!(false);
// println!("-1");
}
}
}
fn main() {
run();
}
akakimidori