結果

問題 No.1339 循環小数
ユーザー 草苺奶昔草苺奶昔
提出日時 2023-03-30 12:26:12
言語 Go
(1.22.1)
結果
AC  
実行時間 456 ms / 2,000 ms
コード長 2,123 bytes
コンパイル時間 15,818 ms
コンパイル使用メモリ 225,136 KB
実行使用メモリ 10,396 KB
最終ジャッジ日時 2023-10-21 23:00:04
合計ジャッジ時間 20,022 ms
ジャッジサーバーID
(参考情報)
judge10 / judge9
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 1 ms
4,348 KB
testcase_01 AC 1 ms
4,348 KB
testcase_02 AC 2 ms
4,348 KB
testcase_03 AC 2 ms
4,348 KB
testcase_04 AC 1 ms
4,348 KB
testcase_05 AC 2 ms
4,348 KB
testcase_06 AC 1 ms
4,348 KB
testcase_07 AC 2 ms
4,348 KB
testcase_08 AC 2 ms
4,348 KB
testcase_09 AC 2 ms
4,348 KB
testcase_10 AC 1 ms
4,348 KB
testcase_11 AC 3 ms
4,348 KB
testcase_12 AC 4 ms
4,348 KB
testcase_13 AC 3 ms
4,348 KB
testcase_14 AC 3 ms
4,348 KB
testcase_15 AC 3 ms
4,348 KB
testcase_16 AC 3 ms
4,348 KB
testcase_17 AC 4 ms
4,348 KB
testcase_18 AC 3 ms
4,348 KB
testcase_19 AC 3 ms
4,348 KB
testcase_20 AC 3 ms
4,348 KB
testcase_21 AC 254 ms
10,172 KB
testcase_22 AC 284 ms
10,284 KB
testcase_23 AC 285 ms
9,540 KB
testcase_24 AC 258 ms
9,204 KB
testcase_25 AC 280 ms
10,308 KB
testcase_26 AC 279 ms
8,948 KB
testcase_27 AC 276 ms
9,212 KB
testcase_28 AC 291 ms
9,204 KB
testcase_29 AC 238 ms
9,500 KB
testcase_30 AC 264 ms
9,528 KB
testcase_31 AC 421 ms
9,160 KB
testcase_32 AC 432 ms
8,808 KB
testcase_33 AC 279 ms
9,444 KB
testcase_34 AC 154 ms
9,228 KB
testcase_35 AC 456 ms
8,808 KB
testcase_36 AC 267 ms
10,396 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

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
		}

		// !模为1时不存在模逆元
		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 {
	if lower >= higher {
		return -1
	}
	UNIT := e()
	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
}

// 模逆元,注意模为1时不存在逆元
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
}
0