This commit is contained in:
itamar 2026-03-20 18:34:42 +00:00
commit e09e88e69c
Signed by: itamar
GPG key ID: C494AC33A201F9E4
7 changed files with 2333 additions and 0 deletions

192
bigints.nim Normal file
View file

@ -0,0 +1,192 @@
import strutils
const BASE = 1_000_000_000'u64
const BASE_DIGITS = 9
type
BigInt* = object
sign*: int # -1, 0, 1
digits*: seq[uint32] # little endian limbs
proc normalize(a: var BigInt) =
while a.digits.len > 0 and a.digits[^1] == 0:
a.digits.setLen(a.digits.len - 1)
if a.digits.len == 0:
a.sign = 0
elif a.sign == 0:
a.sign = 1
proc big*(x: int): BigInt =
if x == 0:
return BigInt(sign: 0)
var v = abs(x)
result.sign = if x < 0: -1 else: 1
while v > 0:
result.digits.add(uint32(v mod int(BASE)))
v = v div int(BASE)
proc parse*(s: string): BigInt =
var str = s
result.sign = 1
if str[0] == '-':
result.sign = -1
str = str[1..^1]
for i in countdown(str.len, 1, BASE_DIGITS):
let start = max(0, i - BASE_DIGITS)
let chunk = parseInt(str[start..<i])
result.digits.add(uint32(chunk))
result.normalize()
proc cmp(a, b: BigInt): int =
if a.digits.len != b.digits.len:
return cmp(a.digits.len, b.digits.len)
for i in countdown(a.digits.len - 1, 0):
if a.digits[i] != b.digits[i]:
return cmp(a.digits[i], b.digits[i])
return 0
proc `==`*(a, b: BigInt): bool =
a.sign == b.sign and a.digits == b.digits
proc add(a, b: BigInt): BigInt =
var carry: uint64 = 0
let n = max(a.digits.len, b.digits.len)
result.digits = newSeq[uint32](n)
for i in 0..<n:
var x = carry
if i < a.digits.len: x += a.digits[i]
if i < b.digits.len: x += b.digits[i]
result.digits[i] = uint32(x mod BASE)
carry = x div BASE
if carry > 0:
result.digits.add(uint32(carry))
result.sign = 1
result.normalize()
proc sub(a, b: BigInt): BigInt =
var borrow: int64 = 0
result.digits = newSeq[uint32](a.digits.len)
for i in 0..<a.digits.len:
var x = int64(a.digits[i]) - borrow
if i < b.digits.len:
x -= int64(b.digits[i])
if x < 0:
x += int64(BASE)
borrow = 1
else:
borrow = 0
result.digits[i] = uint32(x)
result.sign = 1
result.normalize()
proc `+`*(a, b: BigInt): BigInt =
if a.sign == 0: return b
if b.sign == 0: return a
if a.sign == b.sign:
result = add(a, b)
result.sign = a.sign
else:
let c = cmp(a, b)
if c == 0:
return BigInt(sign: 0)
if c > 0:
result = sub(a, b)
result.sign = a.sign
else:
result = sub(b, a)
result.sign = b.sign
proc `-`*(a, b: BigInt): BigInt =
var nb = b
nb.sign *= -1
a + nb
proc `*`*(a, b: BigInt): BigInt =
if a.sign == 0 or b.sign == 0:
return BigInt(sign: 0)
result.digits = newSeq[uint32](a.digits.len + b.digits.len)
for i in 0..<a.digits.len:
var carry: uint64 = 0
for j in 0..<b.digits.len:
let k = i + j
var cur =
uint64(result.digits[k]) +
uint64(a.digits[i]) * uint64(b.digits[j]) +
carry
result.digits[k] = uint32(cur mod BASE)
carry = cur div BASE
var pos = i + b.digits.len
while carry > 0:
let cur = uint64(result.digits[pos]) + carry
result.digits[pos] = uint32(cur mod BASE)
carry = cur div BASE
inc pos
result.sign = a.sign * b.sign
result.normalize()
proc `$`*(a: BigInt): string =
if a.sign == 0:
return "0"
var parts: seq[string]
for d in a.digits:
parts.add($d)
result = parts[^1]
for i in countdown(parts.len - 2, 0):
result.add(parts[i].align(BASE_DIGITS, '0'))
if a.sign < 0:
result = "-" & result
when isMainModule:
let a = parse("123456789123456789123456789")
let b = parse("987654321987654321987654321")
echo "a = ", a
echo "b = ", b
echo "a + b = ", a + b
echo "a * b = ", a * b

112
fenwick.nim Normal file
View file

@ -0,0 +1,112 @@
type Fenwick*[T] = ref object
arr*: seq[T]
type FenwickMod*[T] = ref object
arr*: seq[T]
m*: int64
proc Fenwick*[T](f: var Fenwick[T], len: int): void =
new(f)
f.arr.newSeq(len)
proc Fenwick*[T](f: var Fenwick[T], len: int, default: T): void =
##ializes a fenwick tree with a constant array, f[i] = default for all i.
new(f)
f.arr.newSeq(len)
for i in 0..<len:
f.arr[i] = default
for i in 1..len:
var j = i + (i and (-i))
if j<=len: f.arr[j-1] += f.arr[i-1]
proc Fenwick*[T](f: var Fenwick[T], default: seq[T]): void =
##Converts the seq into a fenwick tree in O(default.len) time.
new(f)
f.arr = default
for i in 1..default.len:
var j = i + (i and (-i))
if j<=default.len: f.arr[j-1] += f.arr[i-1]
proc Fenwick*[T](f: var FenwickMod[T], len: int, m: int64): void =
new(f)
f.arr.newSeq(len)
f.m = m
proc Fenwick*[T](f: var FenwickMod[T], len: int, default: T): void =
##ializes a fenwick tree with a constant array, f[i] = default for all i.
new(f)
f.arr.newSeq(len)
for i in 0..<len:
f.arr[i] = default
for i in 1..len:
var j = i + (i and (-i))
if j<=len: f.arr[j-1] = (f.arr[j-1] + f.arr[i-1]) mod f.m
proc Fenwick*[T](f: var FenwickMod[T], default: seq[T]): void =
##Converts the seq into a fenwick tree in O(default.len) time.
new(f)
f.arr = default
for i in 1..len:
var j = i + (i and (-i))
if j<=len: f.arr[j-1] = (f.arr[j-1] + f.arr[i-1]) mod f.m
type SomeFenwick*[T] = Fenwick[T] | FenwickMod[T]
proc len*[T](f: SomeFenwick[T]): int = f.arr.len
proc sum*[T](f: Fenwick[T], i: SomeInteger): T =
##Returns f[0] + f[1] + ... + f[i]. Time O(log i).
var ii = i+1
while ii>0:
result += f.arr[ii-1]
ii -= (ii and (-ii))
proc sum*[T](f: FenwickMod[T], i: SomeInteger): int64 =
##Returns f[0] + f[1] + ... + f[i]. Time O(log i).
var ii = i+1
while ii>0:
result += f.arr[ii-1]
result = result mod f.m
ii -= (ii and (-ii))
proc addTo*[T](f: Fenwick[T], i: SomeInteger, x: T): void =
var ii = i+1
while ii<=f.arr.len:
f.arr[ii-1] += x
ii += (ii and (-ii))
proc addTo*[T](f: var Fenwick[T], vals: seq[T]): void =
##Adds vals[i] to f[i] for each i. Time O(vals.len).
var vals = vals
for i in 1..vals.len:
var j = i + (i and (-i))
if j<=vals.len: vals[j-1] = vals[j-1] + vals[i-1]
f.arr[i-1] += vals[i-1]
proc addTo*[T](f: FenwickMod[T], i: SomeInteger, x: T): void =
var ii = i+1
while ii<=f.arr.len:
f.arr[ii-1] += x
f.arr[ii-1] = (f.arr[ii-1] mod f.m).T
ii += (ii and (-ii))
proc addTo*[T](f: var FenwickMod[T], vals: seq[T]): void =
##Adds vals[i] to f[i] for each i. Time O(vals.len).
var vals = vals
for i in 1..vals.len:
var j = i + (i and (-i))
if j<=vals.len: vals[j-1] = (vals[j-1] + vals[i-1]) mod f.m
f.arr[i-1] = (f.arr[i-1] + vals[i-1]) mod f.m
proc `[]`*[T](f: Fenwick[T], i: SomeInteger): T =
if i==0: return f.sum(0)
return f.sum(i) - f.sum(i-1)
proc `[]`*[T](f: FenwickMod[T], i: SomeInteger): T =
##Accesses a single element of the base array. O(log i)
if i==0: return f.sum(0)
return (f.sum(i) - f.sum(i-1) + f.m) mod f.m
proc `[]=`*[T](f: SomeFenwick[T], i: SomeInteger, x: T): void =
f.addTo(i, x-f[i])

1484
graphs.nim Normal file

File diff suppressed because it is too large Load diff

152
nt.nim Normal file
View file

@ -0,0 +1,152 @@
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()

45
segmented.nim Normal file
View file

@ -0,0 +1,45 @@
import math, sequtils
proc simple(limit: int): seq[int] =
var isPrime = newSeq[bool](limit + 1)
for i in 0..limit:
isPrime[i] = true
isPrime[0] = false
isPrime[1] = false
for i in 2..int(sqrt(float(limit))):
if isPrime[i]:
var j = i * i
while j <= limit:
isPrime[j] = false
j += i
result = @[]
for i, prime in isPrime:
if prime:
result.add(i)
proc segmented(L, R: int): seq[int] =
let limit = int(sqrt(float(R)))
let primes = simple(limit)
var isPrime = newSeq[bool](R - L + 1)
for i in 0..<isPrime.len:
isPrime[i] = true
for p in primes:
var start = (L div p) * p
if start < L: start += p
if start == p: start += p
var j = start
while j <= R:
isPrime[j - L] = false
j += p
result = @[]
for i in 0..<isPrime.len:
if isPrime[i] and (i + L >= 2):
result.add(i + L)
let L = 10
let R = 500000000
echo segmented(L, R)

98
segtree.nim Normal file
View file

@ -0,0 +1,98 @@
type SegTree*[T, U] = ref object
len*: int
arr*: seq[T]
shift*: seq[U]
proc SegTree*[T, U](f: var SegTree[T, U], len: int): void =
new(f)
f.len = len
f.arr.newSeq(4*len)
f.shift.newSeq(4*len)
proc build[T, U](f: var SegTree[T, U], v, tl, tr: int, a: seq[T]): void =
if tl==tr:
f.arr[v] = a[tl]
else:
var tm: int = (tl + tr) div 2
f.build(2*v, tl, tm, a)
f.build(2*v+1, tm+1, tr, a)
f.arr[v] = f.arr[2*v] + f.arr[2*v+1]
proc build*[T, U](f: var SegTree[T, U], a: seq[T]): void =
f.build(1, 0, f.len - 1, a)
proc modifyRange[T, U](tl, tr: int, sum: T, x: U, additive: bool): T =
if additive: return sum @ ((tr-tl+1) * x)
else: return sum @ x
proc sum[T, U, R](f: var SegTree[T, U], v, tl, tr, l, r: int, phi: proc (x: T): R, additive: bool): R =
if l>r:
return
if f.shift[v] - f.shift[v] != f.shift[v]: #nonzero
f.arr[v] = modifyRange(tl, tr, f.arr[v], f.shift[v], additive)
if tl!=tr:
f.shift[2*v] = f.shift[2*v] + f.shift[v]
f.shift[2*v+1] = f.shift[2*v+1] + f.shift[v]
f.shift[v] = f.shift[v] - f.shift[v]
if l<=tl and tr<=r: return f.arr[v].phi
elif tl!=tr:
var tm: int = (tl + tr) div 2
return f.sum(2*v, tl, tm, l, min(r, tm), phi, additive) + f.sum(2*v+1, tm+1, tr, max(l, tm+1), r, phi, additive)
proc sum*[T, U, R](f: var SegTree[T, U], i, j: int, phi: proc (x: T): R, additive: bool): R =
return f.sum(1, 0, f.len - 1, i, j, phi, additive)
proc showDetails*[T, U](f: var SegTree[T, U], v: int = 1, tl: int = 0, tr: int = f.len - 1, prefix: string = ""): void =
echo prefix, "(", tl, ", ", tr, "): ", f.arr[v], ", ", f.shift[v]
if tl != tr:
var tm: int = (tl + tr) div 2
f.showDetails(2*v, tl, tm, prefix & " ")
f.showDetails(2*v+1, tm+1, tr, prefix & " ")
proc applyTo[T, U](f: var SegTree[T, U], v, tl, tr, l, r: int, x: U, additive: bool): void =
if f.shift[v] - f.shift[v] != f.shift[v]: #nonzero
f.arr[v] = modifyRange(tl, tr, f.arr[v], f.shift[v], additive)
if tl != tr:
f.shift[2*v] = f.shift[2*v] + f.shift[v]
f.shift[2*v+1] = f.shift[2*v+1] + f.shift[v]
f.shift[v] = f.shift[v] - f.shift[v]
if tl>tr or tl>r or tr<l: return
if l<=tl and tr<=r:
f.arr[v] = modifyRange(tl, tr, f.arr[v], x, additive)
if tl != tr:
f.shift[2*v] = f.shift[2*v] + x
f.shift[2*v+1] = f.shift[2*v+1] + x
elif tl!=tr:
var tm: int = (tl + tr) div 2
f.applyTo(2*v, tl, tm, l, min(r, tm), x, additive)
f.applyTo(2*v+1, tm+1, tr, max(l, tm+1), r, x, additive)
f.arr[v] = f.arr[2*v] + f.arr[2*v+1]
proc addTo*[T, U](f: var SegTree[T, U], i, j: int, x: U): void =
f.applyTo(1, 0, f.len - 1, i, j, x, true)
proc multTo*[T, U](f: var SegTree[T, U], i, j: int, x: U): void =
f.applyTo(1, 0, f.len - 1, i, j, x, false)
proc toBaseArray*[T, U, R](f: var SegTree[T, U], phi: proc (x: T): R, additive: bool): seq[R] =
result.newSeq(f.len)
for i in 0..<f.len:
result[i] = f.sum(i, i, phi, additive)
when isMainModule:
proc `@`(x, y: int): int = x + y
var seg: SegTree[int, int]
seg.SegTree(10)
var a: seq[int] = @[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
seg.build(a)
seg.showDetails
proc phi(x: int): int = x
seg.addTo(1, 8, 4)
seg.showDetails
seg.addTo(3, 9, 4)
seg.showDetails
for i in 0..9:
echo i, ": ", seg.sum(i, i, phi, true)

250
sieve.nim Normal file
View file

@ -0,0 +1,250 @@
import math
type
Factor* = object
prime*: uint64
power*: uint64
Factors* = object
numPrimes*: uint64
factors*: seq[Factor]
U64Array* = object
elems*: seq[uint64]
# =========================
# Utilities
# =========================
proc factorAppend*(f: var Factors, p, k: uint64) =
f.factors.add Factor(prime: p, power: k)
inc f.numPrimes
# =========================
# Math helpers
# =========================
proc u64Pow*(a, e: uint64): uint64 =
var base = a
var exp = e
var r: uint64 = 1
while exp > 0:
if (exp and 1) == 1:
r *= base
base *= base
exp = exp shr 1
r
proc u64NthRoot*(x, n: uint64): uint64 =
uint64(pow(float64(x), 1.0 / float64(n)))
proc u64Binom*(n, k: uint64): uint64 =
if k > n: return 0
var r: uint64 = 1
for i in 1..k:
r = r * (n - k + i) div i
r
proc i64Gcd*(a, b: int64): int64 =
var x = a
var y = b
while y != 0:
let t = x mod y
x = y
y = t
x
proc i64Lcm*(a, b: int64): int64 =
(a div i64Gcd(a, b)) * b
proc i64Egcd*(a, b: int64, x, y: var int64): int64 =
if b == 0:
x = 1
y = 0
return a
var x1, y1: int64
let g = i64Egcd(b, a mod b, x1, y1)
x = y1
y = x1 - y1 * (a div b)
g
# =========================
# Prime estimate helpers
# =========================
proc maxPrimeDivs*(max: uint64): uint64 =
let primorials = [
6'u64,30,210,2310,30030,
510510,9699690,223092870
]
for i, p in primorials:
if max < p:
return uint64(i+1)
15
proc maxPrimesLe*(max: uint64): uint64 =
uint64(1.25506 * float64(max) / ln(float64(max)))
# =========================
# Omega sieve
# =========================
proc sieveOmega*(max: uint64): seq[uint8] =
result = newSeq[uint8](max+1)
for n in 2..max:
if result[n] != 0: continue
var m = n
while m <= max:
inc result[m]
m += n
# =========================
# Largest prime factor sieve
# =========================
proc sieveLargestFactors*(max: uint64): seq[uint64] =
result = newSeq[uint64](max+1)
for p in 2..max:
if result[p] != 0: continue
var m = p
while m <= max:
result[m] = p
m += p
# =========================
# Smallest prime factor sieve
# =========================
proc sieveSmallestFactors*(max: uint64): seq[uint32] =
result = newSeq[uint32](max+1)
let r = uint64(sqrt(float64(max)))
for p in 2..r:
if result[p] != 0: continue
var m = p*p
while m <= max:
if result[m] == 0:
result[m] = uint32(p)
m += p
for i in 2..max:
if result[i] == 0:
result[i] = uint32(i)
# =========================
# Factorization
# =========================
proc fillFactorsFromSmallest*(res: var Factors, n: uint64, spf: seq[uint32]) =
var x = n
res.numPrimes = 0
res.factors.setLen(0)
while x > 1:
let p = uint64(spf[x])
var k: uint64 = 0
while spf[x] == uint32(p):
x = x div p
inc k
factorAppend(res, p, k)
# =========================
# Totient sieve
# =========================
proc sievePhi*(max: uint64): seq[uint64] =
result = newSeq[uint64](max+1)
for i in 1..max:
result[i] = i
for p in 2..max:
if result[p] != p: continue
var m = p
while m <= max:
result[m] -= result[m] div p
m += p
# =========================
# Sigma_0 (divisor count)
# =========================
proc sigma0*(max: uint64): seq[uint64] =
result = newSeq[uint64](max+1)
for i in 1..max:
var j = i
while j <= max:
inc result[j]
j += i
# =========================
# Mobius sieve
# =========================
proc mobius*(max: uint64): seq[int8] =
result = newSeq[int8](max+1)
for i in 1..max:
result[i] = 1
for p in 2..max:
if result[p] == 1:
var m = p
while m <= max:
result[m] = -result[m]
m += p
let p2 = p*p
m = p2
while m <= max:
result[m] = 0
m += p2
# =========================
# Prime sieve
# =========================
proc sievePrimes*(max: uint64): seq[uint64] =
var isComp = newSeq[bool](max+1)
for p in 2..max:
if isComp[p]: continue
result.add p
if p*p <= max:
var m = p*p
while m <= max:
isComp[m] = true
m += p
# =========================
# Main
# =========================
when isMainModule:
let max = 10_000_000'u64
let primes = sievePrimes(max)
echo "Primes up to ", max, ":"
for p in primes:
stdout.write($p & " ")
echo ""
let phi = sievePhi(max)
echo "phi(36) = ", phi[36]
let mu = mobius(max)
echo "mu(30) = ", mu[30]