結果
| 問題 | No.1339 循環小数 |
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2023-03-20 18:03:18 |
| 言語 | Go (1.23.4) |
| 結果 |
AC
|
| 実行時間 | 470 ms / 2,000 ms |
| コード長 | 3,214 bytes |
| コンパイル時間 | 14,407 ms |
| コンパイル使用メモリ | 235,908 KB |
| 実行使用メモリ | 9,580 KB |
| 最終ジャッジ日時 | 2024-09-18 14:08:33 |
| 合計ジャッジ時間 | 20,590 ms |
|
ジャッジサーバーID (参考情報) |
judge1 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 1 |
| other | AC * 36 |
ソースコード
package main
import (
"bufio"
"fmt"
"math"
"os"
)
func main() {
// https://yukicoder.me/problems/no/1339
// 求有理数1/n的循环节长度
in := bufio.NewReader(os.Stdin)
out := bufio.NewWriter(os.Stdout)
defer out.Flush()
var T int
fmt.Fscan(in, &T)
for t := 0; t < T; t++ {
var n int
fmt.Fscan(in, &n)
// 让模与10互质
for n%2 == 0 {
n /= 2
}
for n%5 == 0 {
n /= 5
}
if n == 1 {
fmt.Fprintln(out, 1)
continue
}
// !求解 10^k mod n = 1 的最小整数解 k, 其中 1<=k<=n+1
k := DiscreteLogGroup(
func() G { return 1 % n },
func(g1, g2 G) G { return g1 * g2 % n },
func(g G) G { return modInv(g, n) },
10,
1,
1,
n+10,
)
fmt.Fprintln(out, k)
}
}
type G = int
// 给定一个群G,群元素a, b in G,求解 a^n = b 的最小非负整数解 n.
// 返回在[lower, higher)中的第一个解,如果不存在则返回-1.
// !可以理解为 a 经过多少次群运算后可以到达 b.
func DiscreteLogGroup(
/** 群G */
e func() G,
op func(g1, g2 G) G,
inv func(g G) G,
a G,
b G,
lower, higher int,
) int {
aInv := inv(a)
UNIT := e()
if op(a, aInv) != UNIT {
panic("a is not invertible")
}
if lower >= higher {
return -1
}
s := UNIT
mp := make(map[G]int)
aPow := func(n int) G {
p := a
res := UNIT
for n > 0 {
if n&1 == 1 {
res = op(res, p)
}
p = op(p, p)
n /= 2
}
return res
}
s = op(s, aPow(lower))
LIM := higher - lower
K := int(math.Sqrt(float64(LIM))) + 1
for i := 0; i <= K; i++ {
key := s
if _, ok := mp[key]; !ok {
mp[key] = i
}
if i != K {
s = op(s, a)
}
}
a = inv(aPow(K))
for i := 0; i <= K; i++ {
key := b
if v, ok := mp[key]; ok {
res := i*K + v + lower
if res >= higher {
return -1
}
return res
}
b = op(b, a)
}
return -1
}
func exgcd(a, b int) (gcd, x, y int) {
if b == 0 {
return a, 1, 0
}
gcd, y, x = exgcd(b, a%b)
y -= a / b * x
return
}
func modInv(a, mod int) int {
gcd, x, _ := exgcd(a, mod)
if gcd != 1 {
panic(fmt.Sprintf("no inverse element for %d", a))
}
return (x%mod + mod) % mod
}
// 求离散对数 a^n = b (mod m) 的最小非负整数解 n.
// 其中模数为质数.
// 如果不存在则返回-1.
func ModLog(a, b, mod int) int {
a %= mod
b %= mod
p := 1 % mod
for k := 0; k < 32; k++ {
if p == b {
return k
}
p = p * a % mod
}
if a == 0 || b == 0 {
return -1
}
gcd := func(a, b int) int {
for b != 0 {
a, b = b, a%b
}
return a
}
g := gcd(mod, p)
if b%g != 0 {
return -1
}
mod /= g
a %= mod
b %= mod
if gcd(b, mod) > 1 {
return -1
}
return DiscreteLogGroup(
func() G { return 1 % mod },
func(g1, g2 G) G { return (g1 * g2) % mod },
func(g G) G { return modInv(g, mod) },
a,
b,
32,
mod,
)
}
func testModLog() {
// https://www.luogu.com.cn/problem/P4195
in := bufio.NewReader(os.Stdin)
out := bufio.NewWriter(os.Stdout)
defer out.Flush()
for {
var base, p, target int
_, _ = fmt.Fscan(in, &base, &p, &target)
if base == target && target == p && p == 0 {
break
}
res := ModLog(base, target, p)
if res == -1 {
fmt.Fprintln(out, "No Solution")
} else {
fmt.Fprintln(out, res)
}
}
}