nim-lib/nt.nim
2026-03-20 18:34:42 +00:00

152 lines
No EOL
3.2 KiB
Nim

import std/[sequtils]
const MOD* = 1000000007
type ll* = int64
proc reduce*(x: ll): ll =
var r = x mod MOD
if r < 0: r += MOD
r
proc bexp*(b: ll, p: ll): ll =
var
curr = reduce(b)
power = p
res: ll = 1
while power > 0:
if (power and 1) == 1:
res = (res * curr) mod MOD
curr = (curr * curr) mod MOD
power = power shr 1
res
proc inv*(x: ll): ll =
bexp(x, MOD - 2)
type
Combinatorics*[N: static[int]] = object
factorialCache: array[N+1, ll]
inverseFactorialCache: array[N+1, ll]
proc initCombinatorics*[N: static[int]](): Combinatorics[N] =
var c: Combinatorics[N]
c.factorialCache[0] = 1
for i in 1..N:
c.factorialCache[i] = (c.factorialCache[i-1] * i) mod MOD
c.inverseFactorialCache[N] = inv(c.factorialCache[N])
for i in countdown(N-1, 0):
c.inverseFactorialCache[i] =
((i+1).ll * c.inverseFactorialCache[i+1]) mod MOD
c
proc fact*[N](c: Combinatorics[N], x: int): ll =
c.factorialCache[x]
proc ifact*[N](c: Combinatorics[N], x: int): ll =
c.inverseFactorialCache[x]
proc permute*[N](c: Combinatorics[N], n, k: int): ll =
if k > n: return 0
(c.fact(n) * c.ifact(n-k)) mod MOD
proc choose*[N](c: Combinatorics[N], n, k: int): ll =
if k > n: return 0
(((c.fact(n) * c.ifact(k)) mod MOD) * c.ifact(n-k)) mod MOD
proc gcd*(a, b: ll): ll =
if b == 0: a else: gcd(b, a mod b)
proc lcm*(a, b: ll): ll =
(a div gcd(a,b)) * b
type
EGCDResult* = object
x*: ll
y*: ll
d*: ll
proc extendedGcd*(a, b: ll): EGCDResult =
if b == 0:
return EGCDResult(x: 1, y: 0, d: a)
let next = extendedGcd(b, a mod b)
EGCDResult(
x: next.y,
y: next.x - (a div b) * next.y,
d: next.d
)
type
FactorSieve*[N: static[int]] = object
sieve: array[N+1, int]
proc initFactorSieve*[N: static[int]](): FactorSieve[N] =
var s: FactorSieve[N]
s.sieve[1] = 1
for i in 2..N:
if s.sieve[i] == 0:
for j in countup(i, N, i):
s.sieve[j] = i
s
proc factor*[N](s: FactorSieve[N], x0: int): seq[(int,int)] =
var x = x0
var res: seq[(int,int)] = @[]
while x != 1:
let curr = s.sieve[x]
var cnt = 0
while s.sieve[x] == curr:
inc cnt
x = x div curr
res.add((curr,cnt))
res
type
BooleanSieve*[N: static[int]] = object
isComposite: array[N+1, bool]
proc initBooleanSieve*[N: static[int]](): BooleanSieve[N] =
var s: BooleanSieve[N]
s.isComposite[1] = true
for i in 2..N:
if not s.isComposite[i]:
for j in countup(2*i, N, i):
s.isComposite[j] = true
s
proc isPrime*[N](s: BooleanSieve[N], x: int): bool =
not s.isComposite[x]
# ---------------- MAIN ----------------
proc main() =
let comb = initCombinatorics[100000]()
echo "10 choose 3 = ", comb.choose(10,3)
echo "gcd(48,18) = ", gcd(48,18)
echo "lcm(48,18) = ", lcm(48,18)
let eg = extendedGcd(48,18)
echo "extended gcd: x=", eg.x, " y=", eg.y, " d=", eg.d
let sieve = initFactorSieve[100000]()
echo "Factors of 84: ", sieve.factor(84)
let bs = initBooleanSieve[100000]()
echo "Is 97 prime? ", bs.isPrime(97)
when isMainModule:
main()