library_for_python

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub Kazun1998/library_for_python

:heavy_check_mark: Modulo
(Modulo.py)

Theory

定義

$\mathbb{Z}$ を整数環とし, $m$ を正の整数とする. このとき, $m \mathbb{Z}$ は $\mathbb{Z}$ のイデアルであるから, 剰余環 $\mathbb{Z}/m \mathbb{Z}$ を考えることができる.

$x \in \mathbb{Z}$ の属する類を $[x], [x]_m$ と書くことにする. このとき, $x,y \in \mathbb{Z}$ に対して, 以下は同値になる.

よって, 各整数の余りを考えることにより,

\[\mathbb{Z}/m\mathbb{Z}=\{[0], [1], \dots, [m-1] \}\]

となることがわかる.

この剰余環は次の和と積によって可換環になる.

$[x] \in \mathbb{Z}/m \mathbb{Z}$ が可逆元になることの必要十分条件は $x,m$ が互いに素になることである.

よって, $\mathbb{Z}/m\mathbb{Z}$ が体になることの必要十分条件は $m$ が素数であることである.

中国剰余定理

$m$ の素因数分解を $m=p_1^{e_1} \dots p_k^{e_k}$ とする. このとき, 中国剰余定理から

\[\displaystyle \mathbb{Z}/m\mathbb{Z} \simeq \prod_{i=1}^k (\mathbb{Z}/p_i^{e_i} \mathbb{Z})\]

である. このとき, 同型写像 $\varphi$ として

\[\varphi([x]):=([x \bmod{p_1^{e_1}}]_{p_1^{e_1}}, \dots, [x \bmod{p_k^{e_k}}]_{p_k^{e_k}})\]

が挙げられる.

剰余の合成

$x \in \mathbb{Z}$ としたとき,

\[x \equiv a \pmod{m} \cdots (\spadesuit), \quad x \equiv b \pmod{n} \cdots (\heartsuit)\]

を共にみたすような整数 $x$ の特徴づけをする (中国剰余定理の節における $\varphi$ の逆関数の構成).

$(\spadesuit), (\heartsuit)$ を書き換えると,

となることから, 合わせると

ということになる. 式変形をし, $d:=b-a$ とおくと,

となる. このような整数 $p,q$ が存在することの必要十分条件は $d$ が $g:=\gcd(m,n)$ の倍数であることである.

以降, $d$ が $\gcd(m,n)$ の倍数であるとし, 整数 $m’,n’,d’$ をそれぞれ

\[m=gm', \quad n=gn', \quad d=gd'\]

とすると, $(\diamondsuit)$ は $mp \equiv d \pmod{n}$ と同値である.

$m,n,d$ は全て $g$ の倍数であるから, $m’p \equiv d’ \pmod{n’}$ と同値になる.

$m’, n’$ は互いに素であるので, $m’ k \equiv 1 \pmod{n’}$ となる整数 $k$ が存在する. これを両辺にかけることにより,

\[p \equiv dk \pmod{n'}\]

を得る.

これを $x=a+mp$ に代入することによって, $mn’=\dfrac{mn}{\gcd(m,n)}=\operatorname{lcm}(m,n)$ であるから,

\[x \equiv a+mdk \pmod{\operatorname{lcm}(m,n)}\]

を得る. 逆に, これを満たす整数 $x$ は全て $(\spadesuit), (\heartsuit)$ を満たす.

線形方程式

$ax \equiv b \pmod{m}$ を満たす整数 $x$ の特徴づけを行う.

まず, $b$ が $g:=\gcd(a,m)$ の倍数でない場合はこのような整数 $x$ は存在しない. 整数 $a’, b’, m’$ は $a=ga’, b=gb’, m=gm’$ を満たすようにとる.

このとき, $a’, m’$ は互いに素なので, $a’k \equiv 1 \pmod{m’}$ なる整数 $k$ が存在する. よって,

\[ax \equiv b \pmod{m} \iff x \equiv bk \pmod{m'}\]

となる.

ルジャンドル記号

$p$ を素数とする. 整数 $a \in \mathbb{Z}$ におけるルジャンドル記号 $\displaystyle \left( \dfrac{a}{p} \right)$ を

\[\left( \dfrac{a}{p} \right) \equiv a^{(p-1)/2} \pmod{p}, \quad \left( \dfrac{a}{p} \right) \in \{-1,0,1\}\]

をみたす (唯一の) 整数と定義する (well-defindness はフェルマーの小定理より従う).

このとき,

よって, $a$ が $p$ を法にして平方剰余であることと, $\left( \dfrac{a}{p} \right) \neq -1$ であることは同値になる.

位数

$[a] \in \mathbb{Z}/m \mathbb{Z}$ に対して, $[a]^n=[1]$ となる 正の整数 $n$ が存在するか? 存在するならばその $n$ の最小値 $\operatorname{ord} [a]$を求める.

まず, 存在性については $[a]^n=[1]$ が存在することと, $[a]$ が可逆である. つまり, $a,m$ が互いに素になることが同値になる.

実際, $[a]^n=[1]$ となる正の整数 $n$ が存在するならば, $[a]^{-1}=[a]^{n-1}$ であるから, $[a]$ は可逆である. 一方で, $[a]$ が可逆であるとき, $[a]^0, [a]^1, \dots, [a]^m$ には鳩ノ巣原理から, $0 \leq i<j \leq m$ で $[a]^i=[a]^j$ となるようなものが存在する. $[a]$ は可逆と仮定しているので, $[a]^{j-i}=[1]$ である.

可逆元 $[a]$ に対して, 積に関して生成される $\left \langle [a] \right \rangle$ は $(\mathbb{Z}/m\mathbb{Z})^\times$ の部分群である. このとき, ラグランジュの定理から次のことが従う.

また, この2つの群の位数について,

が成り立つ.

以上のことから,

\[\operatorname{ord} [a]=\min \{d \mid 1 \leq d \leq m, d~|~\varphi(m), [a]^d=1 \}\]

となる.

原始根

次のような定理がある.

原始根の存在定理

$p$ を素数とする. このとき, $\mathbb{Z}/p \mathbb{Z}$ には位数 $(p-1)$ の元が存在する.

このような元のことを原始根という.

$p$ を素数とすると, 任意の $p$ の倍数ではない整数 $a$ に対して, $[x]^{p-1}=[1]$ である.

$[g] \in (\mathbb{Z}/p \mathbb{Z})^\times$ が原始根であることの必要十分条件は任意の $(p-1)$ の素因数 $q$ に対して, $[a]^{(p-1)/q} \neq [1]$ となることである.

参考ページ

Verified with

Code

class Modulo:
    __slots__ = ("_a", "_n")

    @property
    def a(self) -> int:
        return self._a

    @property
    def n(self) -> int:
        return self._n

    def __init__(self, a: int, n: int, mode: bool = True):
        if mode:
            a %= n

        self._a = a
        self._n = n

    def __str__(self) -> str:
        return f"{self.a} (mod {self.n})"

    def __repr__(self) -> str:
        return f"{self.__class__.__name__}({self.a}, {self.n})"

    #+,-
    def __pos__(self) -> "Modulo":
        return self

    def __neg__(self) -> "Modulo":
        return Modulo(self.n - self.a, self.n, False) if self.a else Modulo(0, self.n, False)

    #等号,不等号
    def __eq__(self, other: "Modulo") -> bool:
        if isinstance(other, Modulo):
            return (self.a == other.a) and (self.n == other.n)
        elif isinstance(other, int):
            return (self.a - other) % self.n == 0

    def __neq__(self, other: "Modulo") -> bool:
        return not(self == other)

    def __le__(self, other: "Modulo") -> bool:
        a, p = self.a, self.n
        b, q = other.a, other.n
        return (a - b) % q == 0 and p % q == 0

    def __ge__(self, other: "Modulo") -> bool:
        return other <= self

    def __lt__(self, other: "Modulo") -> bool:
        return (self <= other) and (self != other)

    def __gt__(self, other: "Modulo") -> bool:
        return (self >= other) and (self != other)

    def __contains__(self, val) -> bool:
        return val % self.n == self.a

    #加法
    def __add__(self, other: "Modulo") -> "Modulo":
        if isinstance(other,Modulo):
            assert self.n==other.n, "異なる法同士の演算です."
            y=other.a
        elif isinstance(other,int):
            y=other%self.n

        b=self.a+y
        if self.n<=b:
            b-=self.n
        return Modulo(b,self.n, False)

    def __radd__(self, other: "Modulo") -> "Modulo":
        if isinstance(other,int):
            b=self.a+(other%self.n)
            if b>=self.n:
                b-=self.n
            return Modulo(b,self.n, False)

    def __iadd__(self, other: "Modulo") -> "Modulo":
        if isinstance(other,Modulo):
            assert self.n==other.n, "異なる法同士の演算です."
            y=other.a
        elif isinstance(other,int):
            y=other%self.n

        self.a+=y
        if self.a>=self.n:
            self.a-=self.n
        return self

    #減法
    def __sub__(self, other: "Modulo") -> "Modulo":
        if isinstance(other,Modulo):
            assert self.n==other.n, "異なる法同士の演算です."
            y=other.a
        elif isinstance(other,int):
            y=other%self.n

        b=self.a-y
        if b<0:
            b+=self.n
        return Modulo(b,self.n, False)

    def __rsub__(self, other: "Modulo") -> "Modulo":
        if isinstance(other,int):
            b=other%self.n-self.a
            if b<0:
                b+=self.n
            return Modulo(b,self.n, False)

    def __isub__(self, other: "Modulo") -> "Modulo":
        if isinstance(other,Modulo):
            assert self.n==other.n, "異なる法同士の演算です."
            y=other.a
        elif isinstance(other,int):
            y=other%self.n

        self.a-=y
        if self.a<0:
            self.a+=self.n
        return self

    #乗法
    def __mul__(self, other: "Modulo") -> "Modulo":
        if isinstance(other,Modulo):
            assert self.n==other.n, "異なる法同士の演算です."
            y=other.a
        elif isinstance(other,int):
            y=other%self.n

        return Modulo((self.a*y)%self.n, self.n, False)

    def __rmul__(self, other: "Modulo") -> "Modulo":
        if isinstance(other,int):
            return Modulo((self.a*other)%self.n, self.n, False)

    def __imul__(self, other: "Modulo") -> "Modulo":
        if isinstance(other,Modulo):
            assert self.n==other.n, "異なる法同士の演算です."
            y=other.a
        elif isinstance(other,int):
            y=other%self.n

        self.a*=y
        self.a%=self.n
        return self

    #Modulo逆数
    def inverse(self) -> "Modulo":
        return self.modulo_inverse()

    def modulo_inverse(self) -> "Modulo":
        try:
            return Modulo(pow(self.a, -1, self.n), self.n, False)
        except ValueError:
            raise ValueError(f"{self} の逆数が存在しません") from None

    #除法
    def __truediv__(self,other) -> "Modulo":
        return self*(other.modulo_inverse())

    def __rtruediv__(self,other) -> "Modulo":
        return other*(self.modulo_inverse())

    #累乗
    def __pow__(self, other: int) -> "Modulo":
        if isinstance(other, int):
            return Modulo(pow(self.a, other, self.n), self.n, False)
        else:
            b,n=other.a,other.n
            assert pow(self.a,n,self.n)==1, "矛盾なく定義できません."
            return self**b

"""
初等的
"""
def Modulo_Inverse_List(M:int,K:int):
    """
    1^(-1), 2^(-1), ... , K^(-1) (mod N) のリストを出力する.

    [入力]
    M,K:整数
    M>0, K>=1
    K=min(M-1,K) に変換される.

    [出力]
    長さ K+1 のリスト F
    k=1,2,...,K に対して, F[k]=k^(-1) mod M
    また, k^(-1) mod M が存在しない場合, F[k]=None
    """

    assert M>0 and K>=1

    if K==None:
        K=M-1
    K=min(K,M-1)

    F=[None,Modulo(1,M)]
    for k in range(2,K+1):
        q,r=divmod(M,k)
        if F[r]!=None:
            F.append(-q*F[r])
        else:
            F.append(None)
    return F

#細分化
def Subdivision(X:Modulo,M:int):
    """ X をx (mod M) の形に細分化する.

    X.n | Mでなくてはならない.
    """

    assert M%X.n==0,"X.n | M ではありません."

    k=M//X.n
    return [Modulo(X.n*i+X.a,M) for i in range(k)]

#退化
def Degenerate(X:Modulo, M:int):
    """ X の情報を退化させる. X=x (mod N) であるとき, mod M での情報に退化させる.

    M | X.n でなくてはならない.
    """

    assert X.n%M==0,"M | X.n ではありません."
    return Modulo(X.a%M,M)

def Chinese_Remainder(X: Modulo):
    """ 中国剰余定理により, Xを分解する.

    """

    Y=[]

    a,N=X.a,X.n
    e=(N&(-N)).bit_length()-1
    if e>0:
        N>>=e
        Y.append(Modulo(a,1<<e))

    e=0
    while N%3==0:
        e+=1
        N//=3

    if e>0:
        Y.append(Modulo(a,pow(3,e)))

    flag=0
    p=5
    while p*p<=N:
        if N%p==0:
            e=0
            while N%p==0:
                e+=1
                N//=p

            Y.append(Modulo(a,pow(p,e)))

        p+=2+2*flag
        flag^=1

    if N>1:
        Y.append(Modulo(a,N))

    return Y

"""
線形合同方程式関連
"""
def Modulo_Composite(*X: Modulo) -> Modulo:
    """ N 個の Modulo の共通部分を求める.

    Returns:
        Modulo: 共通部分
    """

    def composite(p: Modulo, q: Modulo) -> Modulo | None:
        """ 2つの等式 x ≡ p.a (mod p.n), x ≡ q.a (mod q.n) をともに満たす x を全て求める.

        Args:
            p (Modulo):
            q (Modulo):

        Returns:
            Modulo | None: 条件を満たすことが必要十分になる Modulo. 存在しない場合は None
        """
        from math import gcd

        a, n = p.a, p.n
        b, m = q.a, q.n

        d = b - a
        g = gcd(n, m)

        if d % g:
            return None

        n //= g
        m //= g
        d //= g

        s = pow(n, -1, m)

        return Modulo(a + (n * g) * d * s, n * m *g)

    res = Modulo(0, 1)
    for a in X:
        if (res := composite(res, a)) is None:
            break

    return res

def Is_Included(X: Modulo, Y: Modulo):
    """ X を全て満たす整数は Y を全て満たすか?

    X,Y: Modulo
    """
    a,p=X.a,X.n
    b,q=Y.a,Y.n
    return (a-b)%q==0 and p%q==0

#拡張Euclidの互除法
def Extended_Euclid(a: int, b: int) -> tuple[int, int, int]:
    """ a x + b y = gcd(a, b) を満たす整数の組 (x, y) を求める.

    Args:
        a (int): 整数
        b (int): 整数

    Returns:
        tuple[int, int, int]: (x, y, g) は a x + b y = g を満たす.
    """

    from math import gcd
    g = gcd(a, b)
    if g == 0:
        return (0, 0, 0)

    x = pow(a//g, -1, b//g)
    y = - (a*x-g) // b
    return (x, y, g)

#1次合同方程式を解く
def First_Order_Congruent_Equation(a: int, b: int, m: int) -> Modulo:
    """ 1次合同方程式 a x ≡ b (mod m) を求める.

    Args:
        a (int):
        b (int):
        m (int): m != 0

    Returns:
        Modulo: 条件を満たす X が存在しない場合は None.
    """
    from math import gcd

    if m == 0:
        raise ValueError

    g = gcd(a, m)

    # 存在確認
    if b % g:
        return None

    a, b, m = a // g, b // g, m // g
    c = pow(a, -1, m)
    return Modulo(b * c, m)

#1次連立合同方程式を解く
def First_Order_Simultaneous_Congruent_Equation(*X: tuple[int, int, int]) -> Modulo:
    """ 1 次合同方程式 a_i x ≡ b_i (mod m_i) を求める.

    Args:
        X (list[tuple[int, int, int]]): (a, b, m) の形のタプル. (a, b, m) は ax ≡ b (mod m) を意味する.

    Returns:
        Modulo: 解
    """

    equations = []
    for (a, b, m) in X:
        t = First_Order_Congruent_Equation(a, b, m)
        if t is None:
            break

        equations.append(t)

    return Modulo_Composite(*equations)

"""
総和
"""

def Geometric_Sum(X, L, R):
    """ sum_{i=L}^R X^i を求める.

    X: modulo
    0<=L<=R
    """
    assert 0<=L
    if L>R:
        return 0

    a=X.a; m=X.n
    def calc(K):
        """ sum_{i=0}^{K-1} a^i
        """

        if K==0:
            return 0
        elif K%2==0:
            return (1+pow(a, K//2, m))*calc(K//2)%m
        else:
            return (1+a*calc(K-1))%m

    return Modulo(calc(R+1)-calc(L), m)

"""
有限体の操作関連
"""
#ルジャンドル記号
def Legendre(X: Modulo) -> int:
    """ ルジャンドル記号 (a/p) を返す. ※ 法が素数のときのみ成立する.

    Args:
        X (Modulo):

    Returns:
        int:
            X = 0 のときは 0
            X が平方剰余のときは 1
            X が平方非剰余のときは -1
    """
    if 0 in X:
        return 0

    return 1 if pow(X, (X.n - 1) // 2) == 1 else -1

#根号
def Sqrt(X: Modulo) -> Modulo:
    """ r * r = a (mod p) を満たす r を (存在すれば) 求める.

    Args:
        X (Modulo):

    Returns:
        Modulo: 存在しない場合は None, 存在する場合は r * r = a を満たす r (のうちの 1 つ)
    """

    if Legendre(X) == -1:
        return None

    p = X.n
    if X == 0:
        return X
    elif p == 2:
        return X
    elif p % 4 == 3:
        return pow(X, (p + 1) // 4)
    elif p % 8 == 5:
        if pow(X, (p - 1) // 4) == 1:
            return pow(X, (p + 3) // 8)
        else:
            return pow(2, (p - 1) // 4, p) * pow(X, (p + 3) // 8)

    from random import randint as ri
    u = 2
    s = 1
    while (p - 1) % (2 * u) == 0:
        u *= 2
        s += 1
    q = (p - 1) // u

    while True:
        z = Modulo(ri(1, p - 1), p)
        if pow(z, (p - 1) // 2) == -1:
            break

    m, c, t, r = s, pow(z, q), pow(X, q), pow(X, (q + 1) // 2)
    while m > 1:
        if pow(t, pow(2, m - 2)) == 1:
            c = c * c
            m = m - 1
        else:
            c, t, r, m = c * c, c * c * t, c * r, m - 1

    return r

#離散対数
def Discrete_Log(A: Modulo, B: Modulo | int, default: int = -1) -> int | None:
    """ A^x ≡ B を満たす最小の非負整数 x を求める.

    Args:
        A (Modulo): 底
        B (Modulo | int): 真数
        default (int, optional): 存在しないときの返り値. Defaults to -1.

    Raises:
        ValueError: A, B 共に Modulo のときは法を一致させなければならない.

    Returns:
        int | None: A^x ≡ B を満たす最小の非負整数 x (存在しない場合は default).
    """

    A, M = A.a, A.n

    if isinstance(B, int):
        B %= M
    elif isinstance(B, Modulo):
        if M != B.n:
            raise ValueError
        B = B.a % M
    else:
        raise NotImplementedError

    m = 0
    while m * m < M:
        m += 1

    E = set()
    y = B
    for _ in range(m):
        y *= A; y %= M
        E.add(y)

    step = pow(A, m, M)
    head = 1 % M
    count = 0
    for k in range(1, m + 1):
        tail = head
        head = step * head % M

        if head not in E:
            continue

        body = tail
        for n in range((k - 1) * m, k * m):
            if body == B:
                return n

            body = (A * body) % M

        count += 1
        if count == 2:
            break

    return default

def Order(X: Modulo, defalut: int = -1) -> int:
    """ X^k = 1 を満たす最小の正の整数 k を求める (存在しない場合は -1)

    Args:
        X (Modulo): 底
        defalut (int, optional): 存在しない場合の値. Defaults to -1.

    Returns:
        int: X^k を満たす最小の k
    """

    phi=1
    N=X.n

    e=(N&(-N)).bit_length()-1
    if e>0:
        phi=1<<(e-1)
        N>>=e
    else:
        phi=1

    e=0
    while N%3==0:
        e+=1
        N//=3

    if e>0:
        phi*=pow(3,e-1)*2

    flag=0
    p=5
    while p*p<=N:
        if N%p==0:
            e=0
            while N%p==0:
                e+=1
                N//=p

            phi*=pow(p,e-1)*(p-1)

        p+=2+2*flag
        flag^=1

    if N>1:
        phi*=N-1

    a=float("inf")
    k=1
    while k*k<=phi:
        if phi%k==0:
            if k<a and pow(X,k)==1:
                a=k
                break

            if phi//k<a and pow(X,phi//k)==1:
                a=phi//k
        k+=1

    return a if a < float("inf") else defalut

def Primitive_Root(p):
    """ Z/pZ 上の原始根を見つける

    p: 素数
    """
    if p==2:
        return 1
    if p==998244353:
        return 3
    if p==10**9+7:
        return 5
    if p==163577857:
        return 23
    if p==167772161:
        return 3
    if p==469762049:
        return 3

    fac=[]
    q=2
    v=p-1

    while v>=q*q:
        e=0
        while v%q==0:
            e+=1
            v//=q

        if e>0:
            fac.append(q)
        q+=1

    if v>1:
        fac.append(v)

    g=2
    while g<p:
        if pow(g,p-1,p)!=1:
            return None

        flag=True
        for q in fac:
            if pow(g,(p-1)//q,p)==1:
                flag=False
                break

        if flag:
            return g

        g+=1

"""
数え上げ関連
"""
def Factor_Modulo(N, Mod, Mode=0):
    """
    Mode=0: N! (mod Mod) を求める.
    Mode=1: k! (mod Mod) (k=0,1,...,N) のリストも出力する.

    [計算量]
    O(N)
    """

    if Mode==0:
        X=1
        for k in range(1,N+1):
            X*=k; X%=Mod
        return Modulo(X,Mod)
    else:
        L=[Modulo(1,Mod)]*(N+1)
        for k in range(1,N+1):
            L[k]=k*L[k-1]
        return L

def Factor_Modulo_with_Inverse(N, Mod):
    """ k=0,1,...,N に対する k! (mod Mod) と (k!)^(-1) (mod Mod) のリストを出力する.

    [入力]
    N, Mod: 整数
    Mod >0
    [出力]
    長さ N+1 のリストのタプル (F,G): F[k]=k! (mod M), G[k]=(k!)^(-1) (mod M)
    [計算量]
    O(N+log Mod)
    """

    assert Mod>0

    F=Factor_Modulo(N,Mod,Mode=1)
    G=[0]*(N+1)

    G[-1]=F[-1].inverse()
    for k in range(N,0,-1):
        G[k-1]=k*G[k]
    return F,G

def Binomial_Coefficient_Modulo(n: int, r: int, Mod:int):
    """ nCr (mod Mod) を愚直な方法で求める.

    [入力]
    n, r, Mod: 整数
    Mod>0
    [出力]
    nCr (mod Mod)
    [計算量]
    O(r)
    """
    assert Mod>0
    if r<0 or n<r:
        return Modulo(0,Mod)

    X=Y=1

    r=min(r,n-r)
    for i in range(r):
        X*=n-i; X%=Mod
        Y*=r-i; Y%=Mod
    return Modulo(X,Mod)/Modulo(Y,Mod)

def Binomial_Coefficient_Modulo_List(n:int, Mod:int):
    """ n を固定し, r=0,1,...,n としたときの nCr (mod Mod) のリストを出力する.

    [入力]
    n,Mod: 整数
    Mod>0
    [出力]
    [nC0 (mod Mod), nC1 (mod Mod),..., nCn (mod Mod)]
    [計算量]
    O(n)
    """

    assert Mod>0
    L=[Modulo(1,Mod) for _ in range(n+1)]

    I=Modulo_Inverse_List(Mod,n)
    for r in range(1,n+1):
        L[r]=(n+1-r)*I[r]*L[r-1]
    return L

def Pascal_Triangle(N,M):
    """
    0<=n<=N, 0<=r<=n の全てに対して nCr (mod M) のリストを出力する.

    [入力]
    N,M:整数
    M>0
    [出力] (mod M) を省略.
    [[0C0], [1C0, 1C1], ... , [nC0, ... , nCn], ..., [NC0, ..., NCN]]
    [計算量]
    O(N^2)
    """

    X=[Modulo(1,M)]
    L=[[Modulo(1,M)]]
    for n in range(N):
        Y=[Modulo(1,M)]
        for k in range(1,n+1):
            Y.append(X[k]+X[k-1])
        Y.append(Modulo(1,M))
        X=Y
        L.append(Y)
    return L
Traceback (most recent call last):
  File "/opt/hostedtoolcache/Python/3.13.3/x64/lib/python3.13/site-packages/onlinejudge_verify/documentation/build.py", line 71, in _render_source_code_stat
    bundled_code = language.bundle(stat.path, basedir=basedir, options={'include_paths': [basedir]}).decode()
                   ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.13.3/x64/lib/python3.13/site-packages/onlinejudge_verify/languages/python.py", line 96, in bundle
    raise NotImplementedError
NotImplementedError
Back to top page