結果

問題 No.1339 循環小数
ユーザー 草苺奶昔草苺奶昔
提出日時 2023-03-20 18:03:18
言語 Go
(1.22.1)
結果
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
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 1 ms
5,248 KB
testcase_01 AC 2 ms
5,248 KB
testcase_02 AC 2 ms
5,376 KB
testcase_03 AC 2 ms
5,376 KB
testcase_04 AC 2 ms
5,376 KB
testcase_05 AC 1 ms
5,376 KB
testcase_06 AC 1 ms
5,376 KB
testcase_07 AC 2 ms
5,376 KB
testcase_08 AC 2 ms
5,376 KB
testcase_09 AC 1 ms
5,376 KB
testcase_10 AC 1 ms
5,376 KB
testcase_11 AC 5 ms
5,376 KB
testcase_12 AC 5 ms
5,376 KB
testcase_13 AC 5 ms
5,376 KB
testcase_14 AC 5 ms
5,376 KB
testcase_15 AC 5 ms
5,376 KB
testcase_16 AC 4 ms
5,376 KB
testcase_17 AC 5 ms
5,376 KB
testcase_18 AC 5 ms
5,376 KB
testcase_19 AC 4 ms
5,376 KB
testcase_20 AC 4 ms
5,376 KB
testcase_21 AC 250 ms
8,712 KB
testcase_22 AC 287 ms
8,728 KB
testcase_23 AC 277 ms
8,852 KB
testcase_24 AC 256 ms
9,104 KB
testcase_25 AC 282 ms
9,580 KB
testcase_26 AC 277 ms
8,772 KB
testcase_27 AC 273 ms
8,956 KB
testcase_28 AC 284 ms
8,252 KB
testcase_29 AC 238 ms
8,380 KB
testcase_30 AC 250 ms
8,156 KB
testcase_31 AC 426 ms
8,912 KB
testcase_32 AC 429 ms
9,004 KB
testcase_33 AC 277 ms
9,020 KB
testcase_34 AC 151 ms
8,020 KB
testcase_35 AC 470 ms
8,928 KB
testcase_36 AC 263 ms
9,152 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