結果
| 問題 |
No.950 行列累乗
|
| コンテスト | |
| ユーザー |
maspy
|
| 提出日時 | 2019-12-13 23:45:13 |
| 言語 | Python3 (3.13.1 + numpy 2.2.1 + scipy 1.14.1) |
| 結果 |
WA
|
| 実行時間 | - |
| コード長 | 4,177 bytes |
| コンパイル時間 | 186 ms |
| コンパイル使用メモリ | 13,056 KB |
| 実行使用メモリ | 71,472 KB |
| 最終ジャッジ日時 | 2024-06-27 21:55:15 |
| 合計ジャッジ時間 | 37,144 ms |
|
ジャッジサーバーID (参考情報) |
judge1 / judge3 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 2 WA * 2 |
| other | AC * 14 WA * 43 |
ソースコード
import sys
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
import numpy as np
import itertools
MOD = int(readline())
data = list(map(int,read().split()))
A = np.int64(data[:4]).reshape(2,2)
B = np.int64(data[4:]).reshape(2,2)
def make_power_mat(A, L, MOD=MOD):
N = A.shape[0]
assert A.shape == (N,N)
B = L.bit_length()
x = np.empty((1<<B,N,N), np.int64)
x[0] = np.eye(N,dtype=np.int64)
X = A.copy()
for n in range(B):
for i,j in itertools.product(range(N),repeat=2):
x[1<<n:1<<(n+1),i,j] = (x[:1<<n,i,:] * X[:,j] % MOD).sum(axis=1) % MOD
Y = X.copy()
for i,j in itertools.product(range(N),repeat=2):
X[i,j] = (Y[i,:] * Y[:,j] % MOD).sum() % MOD
return x[:L]
def make_power(a, L, MOD=MOD):
B = L.bit_length()
x = np.empty((1<<B), np.int64)
x[0] = 1
for n in range(B):
x[1<<n:1<<(n+1)] = x[:1<<n] * a % MOD
a *= a; a %= MOD
return x[:L]
def BSGS(a,b,MOD):
assert a != 0
M = int(MOD ** .5 + 100)
c = pow(int(a),M,MOD)
d = pow(int(a),MOD-2,MOD)
B = make_power(d,M,MOD)
G = make_power(c,M,MOD)
I = np.in1d(G, b * B % MOD)
if not I.any():
return -1
q = np.where(I)[0][0]
r = np.where(b * B % MOD == G[q])[0][0]
return q * M + r
def solve_naive(A,B,MOD):
X = np.int64([[1,0],[0,1]])
for n in range(1,10**4):
X = np.dot(X,A) % MOD
if (X == B).all():
return n
return -1
def matrix_power(A,n,MOD):
if n == 0:
return np.eye(2,dtype=np.int64)
B = matrix_power(A,n//2,MOD)
B = np.dot(B,B) % MOD
return np.dot(A,B) % MOD if n & 1 else B
def matrix_inverse(A,MOD):
# powerでもよいが
print(A)
det = (A[0,0]*A[1,1] - A[1,0]*A[0,1]) % MOD
B = np.array([
[A[1,1],-A[0,1]],
[-A[1,0],A[0,0]],
])
x = pow(int(det),MOD-2,MOD)
B *= x; B %= MOD
assert np.all(np.dot(A,B) % MOD == np.eye(2,dtype=np.int64))
return B
def solve(A,B,MOD):
if MOD == 2:
return solve_naive(A,B,MOD)
detA = (A[0,0]*A[1,1] - A[1,0]*A[0,1]) % MOD
detB = (B[0,0]*B[1,1] - B[1,0]*B[0,1]) % MOD
trA = (A[0,0] + A[1,1]) % MOD
if detA == 0 and trA == 0:
# べき零
if (A == B).all():
return 1
if (B == 0).all():
return 2
return -1
if detA == 0:
# A^n = t^{n-1}A
I,J = np.where(A != 0); i = I[0]; j = J[0]
a = A[i,j]; b = B[i,j]
k = b * pow(int(a),MOD-2,MOD) % MOD
assert a * k % MOD == b
n = BSGS(trA,k,MOD)
return -1 if n == -1 else n + 1
print('!!')
# det A == 1 に帰着したい
n = BSGS(detA,detB,MOD)
if n == -1:
return -1
e = BSGS(detA,1,MOD)
Ainv = matrix_inverse(A,MOD)
B = np.dot(B,matrix_power(Ainv,n,MOD)) % MOD
A = matrix_power(A,e,MOD)
k = solve_SL2(A,B,MOD)
if k == -1:
return -1
return e * k + n
def to_hash(A):
A = A.astype(object)
return (A[:,0,0] << 96) + (A[:,1,0] << 64) + (A[:,0,1] << 32) + (A[:,1,1])
def solve_SL2(A,B,MOD):
"""
A の固有値を考えると、Aの位数は十分小さいことが分かる
F_pで2固有値 → p-1周期
F_{p^2}で2固有値 → ノルム1にしたのでp+1周期
固有値が重複 → 2乗すると固有値が1 → 2p周期
2p程度で、BGSGをすればよい
"""
U = 2 * MOD
M = int(U ** .5 + 100)
c = matrix_power(A,M,MOD)
d = matrix_inverse(A,MOD)
Baby = make_power_mat(d,M,MOD)
Giant = make_power_mat(c,M,MOD)
BB = np.zeros((M,2,2),np.int64)
for i,j in itertools.product(range(2),repeat=2):
BB[:,i,j] = (Baby[:,i,:] * B[:,j][None,:] % MOD).sum(axis=1) % MOD
Gh = to_hash(Giant).tolist()
BBh = to_hash(BB).tolist()
se = set(BBh)
q = -1
for i,g in enumerate(Gh):
if g in se:
q = i
break
if q == -1:
return -1
g = Gh[q]
r = -1
for i,b in enumerate(BBh):
if b == g:
r = i
break
return q * M + r
print(solve(A,B,MOD))
maspy