結果

問題 No.1105 Many Triplets
ユーザー 👑 hahhohahho
提出日時 2024-08-06 16:50:48
言語 PyPy3
(7.3.15)
結果
AC  
実行時間 60 ms / 2,000 ms
コード長 10,742 bytes
コンパイル時間 362 ms
コンパイル使用メモリ 82,176 KB
実行使用メモリ 70,016 KB
最終ジャッジ日時 2024-08-06 16:50:51
合計ジャッジ時間 3,035 ms
ジャッジサーバーID
(参考情報)
judge4 / judge2
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 40 ms
56,576 KB
testcase_01 AC 39 ms
56,448 KB
testcase_02 AC 41 ms
56,064 KB
testcase_03 AC 41 ms
56,320 KB
testcase_04 AC 39 ms
55,808 KB
testcase_05 AC 42 ms
56,192 KB
testcase_06 AC 40 ms
56,576 KB
testcase_07 AC 60 ms
55,680 KB
testcase_08 AC 43 ms
56,576 KB
testcase_09 AC 43 ms
56,192 KB
testcase_10 AC 55 ms
69,504 KB
testcase_11 AC 53 ms
69,632 KB
testcase_12 AC 51 ms
69,632 KB
testcase_13 AC 52 ms
69,632 KB
testcase_14 AC 52 ms
69,504 KB
testcase_15 AC 52 ms
69,760 KB
testcase_16 AC 52 ms
69,888 KB
testcase_17 AC 52 ms
70,016 KB
testcase_18 AC 52 ms
70,016 KB
testcase_19 AC 53 ms
69,632 KB
testcase_20 AC 37 ms
55,168 KB
testcase_21 AC 37 ms
54,912 KB
testcase_22 AC 36 ms
55,168 KB
testcase_23 AC 37 ms
54,912 KB
testcase_24 AC 37 ms
54,912 KB
testcase_25 AC 38 ms
55,168 KB
testcase_26 AC 44 ms
55,040 KB
testcase_27 AC 38 ms
55,036 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

def modinv(x: int, mod: int) -> int:
    """
    Z/(mod Z)上でのxの逆元

    :param x: 整数
    :param mod: 整数
    :return: x * y % mod = 1を満たすy
    """
    s, ps, r, pr = 0, 1, mod, x
    while r != 0:
        pr, (q, r) = r, divmod(pr, r)
        ps, s = s, ps - q * s
    if pr == 1:
        return ps if ps >= 0 else ps + mod
    raise ValueError("base is not invertible for the given modulus")


def modpow(x, k, mod):
    """
    Z/(mod Z)上でのxのk乗

    :param x: 整数
    :param k: 整数
    :param mod: 整数
    :return: x ** k % mod
    """
    if k < 0:
        x = modinv(x, mod)
        k = -k
    r = 1
    while k != 0:
        if k & 1:
            r = (r * x) % mod
        x = (x * x) % mod
        k >>= 1
    return r

intadd = int.__add__
intsub = int.__sub__
intmul = int.__mul__

MOD = 10**9 + 7

class ModInt(int):

    @classmethod
    def normalized(cls, v):
        return ModInt(v % MOD)

    def __neg__(self):
        return ModInt(intsub(MOD, self) if self != 0 else 0)

    def __add__(self, other):
        x = intadd(self, other)
        return ModInt(x if x < MOD else x - MOD)

    def __sub__(self, other):
        x = intsub(self, other)
        return ModInt(x if x >= 0 else x + MOD)

    def __rsub__(self, other):
        x = intsub(other, self)
        return ModInt(x if x >= 0 else x + MOD)

    def __mul__(self, other):
        return ModInt(intmul(self, other) % MOD)

    def __truediv__(self, other):
        return self * ModInt(other).inv

    def __rtruediv__(self, other):
        return self.inv * other

    __radd__ = __add__
    __rmul__ = __mul__
    __floordiv__ = __truediv__
    __rfloordiv__ = __rtruediv__

    def __pow__(self, other, **kwargs):
        return ModInt(modpow(int(self), int(other), MOD))

    @property
    def inv(self):
        return ModInt(modinv(int(self), MOD))

    @classmethod
    def sum(cls, iterable):
        r = 0
        for v in iterable:
            r += int(v)
        return ModInt(r % MOD)

    @classmethod
    def product(cls, iterable):
        r = ModInt(1)
        for v in iterable:
            r *= v
        return r


class Array2dView:
    def __init__(self, arr, i_indices, j_indices):
        self.arr = arr
        self.i_indices = i_indices
        self.j_indices = j_indices
        self.n = len(i_indices)
        self.m = len(j_indices)

    def _get_view(self, i, j):
        i = self.i_indices[i]
        j = self.j_indices[j]
        return Array2dView(self.arr, i, j)

    def get_ind(self, i, j):
        return self.i_indices[i] + self.j_indices[j]

    def __getitem__(self, index):
        i, j = index
        try:
            return self.arr[self.get_ind(i, j)]
        except TypeError:
            return self._get_view(i, j)

    def __setitem__(self, index, value):
        i, j = index
        try:
            self.arr[self.get_ind(i, j)] = value
        except TypeError:
            x = self._get_view(i, j)
            for i in x.i_indices:
                for j in x.j_indices:
                    self.arr[i + j] = value

    def __iter__(self):
        for i in self.i_indices:
            for j in self.j_indices:
                yield self.arr[i + j]

    def __reversed__(self):
        for i in reversed(self.i_indices):
            for j in reversed(self.j_indices):
                yield self.arr[i + j]

    def __str__(self):
        m = max(len(str(v)) for v in self)
        res = [''] * len(self.i_indices)
        row = [''] * (len(self.j_indices) + 2)
        for ri, i in enumerate(self.i_indices):
            if ri == 0:
                row[0] = '['
            else:
                row[0] = ' '
            if ri == len(self.i_indices) - 1:
                row[-1] = ']\n'
            for rj, j in enumerate(self.j_indices):
                row[rj + 1] = f'{str(self.arr[i + j]):>{m + 1}}'
            res[ri] = ''.join(row)
        return '\n'.join(res)

    def copy(self):
        return Array2d(len(self.i_indices), len(self.j_indices), list(self))

class Array2d:
    def __init__(self, n, m, arr):
        self.n = n
        self.m = m
        self.arr = arr

    @classmethod
    def full(cls, n, m, fill_value):
        return cls(n, m, [fill_value] * (n * m))

    @classmethod
    def from_list(cls, lst):
        n, m = len(lst), len(lst[0])
        arr = [lst[0]] * (n * m)
        k = 0
        for row in lst:
            for v in row:
                arr[k] = v
                k += 1
        return cls(n, m, arr)

    def _get_view(self, i, j):
        i = tuple(range(0, self.n * self.m, self.m))[i]
        j = tuple(range(self.m))[j]
        return Array2dView(self.arr, i, j)

    def get_ind(self, i, j):
        return i * self.m + j

    def __getitem__(self, index):
        try:
            return self.arr[self.get_ind(*index)]
        except TypeError:
            return self._get_view(*index)

    def __setitem__(self, index, value):
        try:
            self.arr[self.get_ind(*index)] = value
        except TypeError:
            x = self._get_view(*index)
            for i in x.i_indices:
                for j in x.j_indices:
                    self.arr[i + j] = value

    def __iter__(self):
        return iter(self.arr)

    def __reversed__(self):
        return reversed(self.arr)

    def __str__(self):
        m = max(len(str(v)) for v in self)
        res = [''] * self.n
        row = [''] * (self.m + 2)
        for i in range(self.n):
            if i == 0:
                row[0] = '['
            else:
                row[0] = ' '
            if i == self.n - 1:
                row[-1] = ']\n'
            for j in range(self.m):
                row[j + 1] = f'{str(self.arr[i * self.m + j]):>{m + 1}}'
            res[i] = ''.join(row)
        return '\n'.join(res)

    __repr__ = __str__

    def __eq__(self, other):
        return self.arr == other.arr

    def copy(self):
        return self.__class__(self.n, self.m, self.arr[:])

    @property
    def t(self):
        arr = [self.arr[0]] * (len(self.arr))
        x = 0
        for i in range(self.n):
            for j in range(self.m):
                arr[j * self.n + i] = self.arr[x]
                x += 1
        return self.__class__(self.m, self.n, arr)


def get_general_matrix(zero, one):
    class Matrix(Array2d):
        ZERO = zero
        ONE = one

        @classmethod
        def zeros(cls, n, m):
            return cls.full(n, m, cls.ZERO)

        @classmethod
        def ones(cls, n, m):
            return cls.full(n, m, cls.ONE)

        def __add__(self, other):
            if self.m != other.m or self.n != other.n:
                raise ValueError(f'Cannot add matrices ({self.n}, {self.m}) and ({other.n}, {other.m})')
            return Matrix(self.n, self.m, [x + y for x, y in zip(self.arr, other.arr)])

        def __iadd__(self, other):
            if self.m != other.m or self.n != other.n:
                raise ValueError(f'Cannot multiply matrices ({self.n}, {self.m}) and ({other.n}, {other.m})')
            for i, v in enumerate(other.arr):
                self.arr[i] += v
            return self

        def __sub__(self, other):
            if self.m != other.m or self.n != other.n:
                raise ValueError(f'Cannot subtract matrices ({self.n}, {self.m}) and ({other.n}, {other.m})')
            return Matrix(self.n, self.m, [x - y for x, y in zip(self.arr, other.arr)])

        def __isub__(self, other):
            if self.m != other.m or self.n != other.n:
                raise ValueError(f'Cannot multiply matrices ({self.n}, {self.m}) and ({other.n}, {other.m})')
            for i, v in enumerate(other.arr):
                self.arr[i] -= v
            return self

        def __mul__(self, other):
            if self.m != other.m or self.n != other.n:
                raise ValueError(f'Cannot multiply matrices ({self.n}, {self.m}) and ({other.n}, {other.m})')
            return Matrix(self.n, self.m, [x * y for x, y in zip(self.arr, other.arr)])

        def __imul__(self, other):
            if self.m != other.m or self.n != other.n:
                raise ValueError(f'Cannot multiply matrices ({self.n}, {self.m}) and ({other.n}, {other.m})')
            for i, v in enumerate(other.arr):
                self.arr[i] *= v
            return self

        def __truediv__(self, other):
            if self.m != other.m or self.n != other.n:
                raise ValueError(f'Cannot multiply matrices ({self.n}, {self.m}) and ({other.n}, {other.m})')
            return Matrix(self.n, self.m, [x / y for x, y in zip(self.arr, other.arr)])

        def __matmul__(self, other):
            if self.m != other.n:
                raise ValueError(f'Cannot dot multiply matrices ({self.n}, {self.m}) and ({other.n}, {other.m})')

            res = self.full(self.n, other.m, self.ZERO)

            for i in range(self.n):
                for j in range(other.m):
                    c = self.ZERO
                    for k in range(self.m):
                        c += self[i, k] * other[k, j]
                    res[i, j] = c
            return res

        def __imatmul__(self, other):
            if self.m != other.n:
                raise ValueError(f'Cannot multiply matrices ({self.n}, {self.m}) and ({other.n}, {other.m})')
            if self is other or self.m != other.m:
                return self @ other

            row = [self.ZERO] * self.m
            for i in range(self.n):
                t = i * self.m
                for j in range(self.m):
                    row[j] = self.arr[j + t]
                for j in range(other.m):
                    c = self.ZERO
                    for k in range(self.m):
                        c += row[k] * other[k, j]
                    self[i, j] = c
            return self

        def __pow__(self, power, modulo=None):
            if self.n != self.m:
                raise ValueError('pow is supported only for square matrix')
            k = self.n
            res = Matrix.full(k, k, self.ZERO)
            for i in range(k):
                res[i, i] = self.ONE

            m = self
            while power > 0:
                if power & 1:
                    res @= m
                m @= m
                power >>= 1
            return res

    return Matrix

modint = ModInt

n = int(input())
a,b,c = map(int, input().split())

M = get_general_matrix(modint(0), modint(1))

m = M.from_list([[modint(1), -modint(1), modint(0),],
                 [modint(0), modint(1), -modint(1),],
                 [-modint(1), modint(0), modint(1),]])
m **= n-1
v = M.from_list([[modint.normalized(a)],[modint.normalized(b)],[modint.normalized(c)]])

v = m@v
print(v[0, 0], v[1, 0], v[2, 0])
0