perarduaadastra

競技プログラミングとかをしています

AtCoder Library Python3, PyPy3用

AtCoderから公式スターターパックが遂に待望のリリース!

やべ〜〜〜〜PythonやめてC++に乗り換える方が楽では?

 

がんばって毎日こつこつ書いて揃えようと思います。名前順とかで書きます。
全部あるかはわかりません。


1. Convolution

mod 998244353に限定したFMT(NTTとも)です。
多項式同士の乗算で各項の係数を求めることができます。nは2冪でa, bの長さより2倍以上大きな値を渡しておき、fmtして得られた数列の同index要素を掛け合わせてifmtすると畳み込みが終了します。重すぎて50万オーダーはさすがに5secでもTLE 7secくらいはいりそう

class FastModuloTransformation:
  def __init__(self, n):
    self.n = n
 
    self.P = 998244353
    self.g = 3
    self.omega = pow(self.g, (self.P - 1) // n, self.P)
  def bitrev(self, a):
    n = self.n
    x = n.bit_length() - 1
    res = a[: ]
    for i in range(n):
      j = 0
      for k in range(x): j |= (i & (1 << k) > 0) << (x - k - 1)
      if i < j: res[i], res[j] = res[j], res[i]
    return res
  def fmt(self, a, base):
    if n == 1: return a
    P = self.P
    omega = base
    A = self.bitrev(a)
    half = pow(omega, n >> 1, P)
    i = n
    m = 1
    while i > 1:
      i >>= 1
      w = pow(omega, i, P)
      wk = 1
      for j in range(m):
        for x in range(j, len(a), 2 * m):
          l = A[x]
          r = wk * A[x + m] % P
          A[x] = (l + r) % P
          A[x + m] = (l + r * half) % P
        wk *= w
        wk %= P
      m <<= 1
    return A
  def ifmt(self, A):
    if self.n == 1: return A
    P = self.P
    nrev = pow(self.n, P - 2, P)
    return [(x * nrev) % P for x in self.fmt(A, pow(self.omega, P - 2, P))]

2. CRT

とど
 

3. Disjoint Set Union

まあただのUnionFindですよね。DSUの方がメジャーな言い方なのかしら。

class DisjointSetUnion():
  def __init__(self, n):
    self.n = n
    self.root = [-1] * (n + 1)
    self.rank = [0] * (n + 1)
  def leader(self, x):
    rt = self.root[x]
    if rt < 0: return x
    else: self.root[x] = self.leader(rt)
    return self.root[x]
  def merge(self, x, y):
    leader = self.leader
    xrt = leader(x)
    yrt = leader(y)
    if xrt == yrt: return
    if self.rank[xrt] > self.rank[yrt]:
      self.root[xrt] += self.root[yrt]
      self.root[yrt] = xrt
    else:
      self.root[yrt] += self.root[xrt]
      self.root[xrt] = yrt
      self.rank[yrt] += self.rank[xrt] == self.rank[yrt]
  def same(self, x, y): return self.leader(x) == self.leader(y)
  def size(self, x):  return -self.root[self.leader(x)]
  def group(self):
    n = self.n
    leader = self.leader
    res = [[] for _ in range(n + 1)]
    for x in range(n + 1): res[leader(x)].append(x)
    return [res[i] for i in range(n + 1) if len(res[i])]

4. Fenwick Tree

indexは[0, n]で使えます。sumは[l, r)の総和を返します。
lowerboundは総和がs以上になるような最小のindexとかを返すやつですがあんまり試していません。

class FenwickTree:
  def __init__(self, n):
    self.n = n
    self.data = [0] * (n + 2)
  def sum(self, l, r):
    s = 0
    while l > 0:
      s -= self.data[l]
      l -= l & -l
    while r > 0:
      s += self.data[r]
      r -= r & -r
    return s
  def add(self, i, x):
    i += 1
    while i <= self.n:
      self.data[i] += x
      i += i & -i
  def lowerbound(self, s):
    x = 0
    y = 0
    for i in range(self.n.bit_length(), -1, -1):
      k = x + (1 << i)
      if k <= self.n and (y + self.data[k] < s):
        y += self.data[k]
        x += 1 << i
    return x + 1

5. Floor Sum

なにこれ?よくわかりませんが一応作りました。

def FloorSum(n, m, a, b):
  # (a * 0 + b) // m + ... + (a * (n - 1) + b) // m
  res = 0
  if a >= m:
    res += (a // m) * n * (n - 1) // 2
    a %= m
  if b >= m:
    res += n * (b // m)
    b %= m
  if a * n + b < m: return res
  u = (a * n + b) // m
  v = (u * m - b)
  res += (n - (v + a - 1) // a) * u + FloorSum(u, a, m, (a - v) % a)
  return res

6. Lazy Segment Tree

とど

7. LCP Array

suffix arrayのLCPが出せます。

def LCPArray(n, s, sa):
  r = [0] * n
  for i in range(n): r[sa[i]] = i
  lcp = [0] * (n - 1)
  x = 0
  for i in range(n):
    if x > 0: x -= 1
    if r[i] == 0: continue
    j = sa[r[i] - 1]
    while max(i, j) + x < n:
      if s[i + x] != s[j + x]: break
      x += 1
    lcp[r[i] - 1] = x
  return lcp 

8. Max Flow

とど

9. Min Cost Flow

とど

10. SCC

とど

11. Segment Tree

とど

12. Sufix Array

induced sortingを使っていません。O(NlogN)くらいです。

def SuffixArray(n, s):
  order = [n - 1 - i for i in range(n)]
  order.sort(key = lambda x: s[x])
  sa = [0] * n
  classes = [0] * n
  for i in range(n):
    sa[i] = order[i]
    classes[i] = S[i]
  k = 1
  while k < n:
    c = classes[: ]
    for i in range(n): 
      if i > 0 and (c[sa[i - 1]] == c[sa[i]]) and ((sa[i - 1] + k) < n) and ((c[sa[i - 1] + k // 2]) == c[sa[i] + k // 2]):
        classes[sa[i]] = classes[sa[i - 1]]
      else: classes[sa[i]] = i
    cc = [i for i in range(n)]
    ss = sa[: ]
    for i in range(n):
      if ss[i] - k >= 0:
        sa[cc[classes[ss[i] - k]]] = ss[i] - k
        cc[classes[ss[i] - k]] += 1
    k <<= 1
  return sa

13. 2-SAT

とど

14. Z-algorithm

ざるごりずむ。各接尾辞に対するLCPがわかる。

def Zalgorithm(S):
  ln = len(S)
  Z = [0] * ln
  Z[0] = ln
  i, j = 1, 0
  while i < ln:
    while i + j < ln and (S[i + j] == S[j]): j += 1
    if j:
      k = 1
      Z[i] = j
      while k < j and (k + Z[k] < j):
        Z[i + k] = Z[k]
        k += 1
      i += k
      j -= k
    else: i += 1
  return Z