152 lines
3.2 KiB
Nim
152 lines
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()
|