Python 尺取法ライブラリ

尺取法ライブラリ

尺取法のPythonライブラリです。英語でTwo Pointersっていうらしいです。 数列のうち、ある条件を満たす部分数列を数え上げたり、最大の長さの部分数列を求めたりすることができます。

from copy import deepcopy
from operator import add, sub
class TwoPointers:
    def __init__(self, cond, init=0, right=add, left=sub):
        self.cond = cond
        self.init = init
        self.next_right = right
        self.next_left = left
    
    def __call__(self, A, uniq=True):
        cond = self.cond
        next_right, next_left = self.next_right, self.next_left
        s = deepcopy(self.init)
        n = len(A)
        X = {}
        r = 0
        for l in range(n):
            if not uniq:
                X[l] = r
            while r < n and cond(s, A[r]):
                s = next_right(s, A[r])
                r += 1
                X[l] = r
            if l == r:
                r += 1
            else:
                s = next_left(s, A[l]) if l+1 != r else deepcopy(self.init)
        return list(X.items())
    
    def maximum(self, A):
        X = self.__call__(A)
        return max(r-l for l, r in X) if X else 0
    
    def count(self, A):
        X = self.__call__(A, False)
        return sum(r-l for l, r in X)

解説

 n ... リストのサイズを指定します。
 \mathrm{maximum}(A) ... 条件を満たすAの部分数列の最大の長さを返します。
 \mathrm{count}(A) ... Aの部分数列で条件を満たすものを数え上げます。

使用例

使用したコードがあれば適宜アップデートしていきます。

AtCoder ABC 032 C - 列

from copy import deepcopy
from operator import add, sub, mul, floordiv
class TwoPointers:
    # Folding

n, k, *S = map(int, open(0).read().split())
if 0 in S:
    print(n)
else:
    tp = TwoPointers(lambda s, n: s*n <= k, 1, mul, floordiv)
    print(tp.maximum(S))

AtCoder ABC 098 D - Xor Sum 2

from copy import deepcopy
from operator import add, sub
class TwoPointers:
    # Folding

n, *A = map(int, open(0).read().split())
print(TwoPointers(lambda s, n: s + n == s ^ n).count(A))

AtCoder ABC 038 C - 単調増加

from copy import deepcopy
from operator import add, sub
class TwoPointers:
    # Folding

n, *A = map(int, open(0).read().split())
tp = TwoPointers(lambda s, n: s < n, 0, lambda s, n: n, lambda s, n: s)
print(tp.count(A))

AtCoder ARC 022 B - 細長いお菓子

from copy import deepcopy
from operator import add, sub
class TwoPointers:
    # Folding
n, *A = map(int, open(0).read().split())
def next_right(s, n):
    s.add(n)
    return s
def next_left(s, n):
    s.remove(n)
    return s
tp = TwoPointers(lambda s, n: n not in s, set(), next_right, next_left)
print(tp.maximum(A))