Skip to content

Conversation

@harry0000
Copy link
Owner

@harry0000 harry0000 commented Oct 21, 2025

Summary

To reduce memory usage, change ModInt to opaque type aliases from case classes

Result

StaticModInt implementation

opaque type StaticModInt[T <: Int] = Int

object StaticModInt {
  inline def apply[T <: Int]()(using Modulus[T]): StaticModInt[T] = 0

  inline def apply[T <: Int](value: Int)(using m: Modulus[T]): StaticModInt[T] = {
    val x = applyIntImpl(value, m.value)
    raw(x)
  }

  inline def apply[T <: Int](value: Long)(using m: Modulus[T]): StaticModInt[T] = {
    val x = applyLongImpl(value, m.value)
    raw(x.toInt)
  }

  private inline def raw[T <: Int](value: Int): StaticModInt[T] = value

  private inline def mul[T <: Int](a: StaticModInt[T], b: StaticModInt[T])(using m: Modulus[T]): StaticModInt[T] = {
    val mod = m.value.toLong
    val res = (a.toLong * b.toLong) % mod
    raw(res.toInt)
  }

  extension [T <: Int](self: StaticModInt[T])(using m: Modulus[T]) {
    // We use `value`. `val` is a reserved word in Scala.
    inline def value: Int = self

    inline def +(rhs: StaticModInt[T]): StaticModInt[T] = {
      raw(addImpl(self, rhs, m.value))
    }

    inline def -(rhs: StaticModInt[T]): StaticModInt[T] = {
      raw(subImpl(self, rhs, m.value))
    }

    inline def *(rhs: StaticModInt[T]): StaticModInt[T] = {
      mul(self, rhs)
    }

    inline def /(rhs: StaticModInt[T]): StaticModInt[T] = {
      mul(self, rhs.inv)
    }

    inline def pow(n: Int): StaticModInt[T] = {
      var _n = n
      var x = self
      var r = apply(1)
      while (_n > 0) {
        if ((_n & 1) == 1) {
          r = mul(r, x)
        }
        x = mul(x, x)
        _n >>= 1
      }
      r
    }

    inline def inv: StaticModInt[T] = {
      if (m.isPrime) {
        assert(self != 0)
        pow(m.value - 2)
      } else {
        val (g, x) = internal.invGcd(self.toLong, m.value.toLong)
        assert(g == 1L)
        apply(x)
      }
    }
  }
}

type ModInt1000000007 = StaticModInt[Mod1000000007.value.type]
type ModInt998244353 = StaticModInt[Mod998244353.value.type]

given mod1000000007Modulus: Modulus[Mod1000000007.value.type] = Mod1000000007
given mod998244353Modulus: Modulus[Mod998244353.value.type] = Mod998244353

object ModInt1000000007 {
  def apply(): ModInt1000000007 = StaticModInt()
  def apply(value: Int): ModInt1000000007 = StaticModInt(value)
  def apply(value: Long): ModInt1000000007 = StaticModInt(value)
}

object ModInt998244353 {
  def apply(): ModInt998244353 = StaticModInt()
  def apply(value: Int): ModInt998244353 = StaticModInt(value)
  def apply(value: Long): ModInt998244353 = StaticModInt(value)
}

@harry0000 harry0000 merged commit 4802c1c into main Oct 21, 2025
3 checks passed
@harry0000 harry0000 deleted the refactor/modint branch October 21, 2025 07:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[perf] investigate performance issue in convolution [perf] investigate performance issue in LazySegtree with ModInt

2 participants