結果

問題 No.1339 循環小数
ユーザー 草苺奶昔草苺奶昔
提出日時 2023-03-20 18:03:18
言語 Go
(1.22.1)
結果
AC  
実行時間 432 ms / 2,000 ms
コード長 3,214 bytes
コンパイル時間 11,613 ms
コンパイル使用メモリ 223,880 KB
実行使用メモリ 10,348 KB
最終ジャッジ日時 2023-10-18 18:10:12
合計ジャッジ時間 17,515 ms
ジャッジサーバーID
(参考情報)
judge14 / judge11
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 1 ms
4,348 KB
testcase_01 AC 1 ms
4,348 KB
testcase_02 AC 1 ms
4,348 KB
testcase_03 AC 2 ms
4,348 KB
testcase_04 AC 2 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 1 ms
4,348 KB
testcase_10 AC 2 ms
4,348 KB
testcase_11 AC 4 ms
4,348 KB
testcase_12 AC 3 ms
4,348 KB
testcase_13 AC 3 ms
4,348 KB
testcase_14 AC 4 ms
4,348 KB
testcase_15 AC 4 ms
4,348 KB
testcase_16 AC 4 ms
4,348 KB
testcase_17 AC 3 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 243 ms
10,320 KB
testcase_22 AC 280 ms
9,208 KB
testcase_23 AC 279 ms
9,812 KB
testcase_24 AC 254 ms
9,208 KB
testcase_25 AC 277 ms
10,316 KB
testcase_26 AC 275 ms
9,256 KB
testcase_27 AC 272 ms
10,344 KB
testcase_28 AC 283 ms
9,860 KB
testcase_29 AC 235 ms
9,480 KB
testcase_30 AC 247 ms
9,276 KB
testcase_31 AC 402 ms
8,960 KB
testcase_32 AC 412 ms
8,964 KB
testcase_33 AC 263 ms
8,792 KB
testcase_34 AC 147 ms
9,248 KB
testcase_35 AC 432 ms
8,644 KB
testcase_36 AC 255 ms
10,348 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
		}

		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)
		}
	}
}
0