LIS
投稿者:CarpDay.icon
1. LISの概要
最長増加部分列問題.Longest Increasing Subsequenceの略.
数列 $ a_1, a_2, ..., a_nから,狭義増加列(前後が等しいのはNG)を作る.
部分列の長さは最長でいくつ?
参考:
https://pydocument.hatenablog.com/entry/2023/04/01/185559
2. 長さiのLISの最後尾数の最小値DP版(Python)
上の参考ページでのやり方.実装方法も2種類ある.
(1) リストの要素を追加するタイプ
code: python
from bisect import bisect_left
n = int(input())
a = int(input()) for _ in range(n)
#dpi: 長さ i のLISの最後の数のうち,最も小さな値
dp = -1
ans = 0
for x in a:
if dp-1 < x: # LISの長さ更新
dp.append(x)
else:
idx = bisect_left(dp, x) # dpidx-1 < x <= dpidx
dpidx = x
print(len(dp) - 1)
(2) リストを最大数だけ確保しておくタイプ
code: python
from bisect import bisect_left
N = int(input())
A = int(input()) for _ in range(N)
INF = float('inf')
dp = INF * (N + 1)
dp0 = -1
for a in A:
idx = bisect_left(dp, a)
dpidx = min(a, dpidx)
# print(dp)
print(max(i for i in range(N + 1) if dpi < INF))
Verified: AOJ: https://onlinejudge.u-aizu.ac.jp/problems/DPL_1_D
2. 最後尾数がiであるLISの長さDP版(Python)
DPの途中段階におけるLISが獲得しやすいDP
セグメント木を使う.
格納する値が要素数より大きい場合は,座標圧縮が必要.
code: python
# 座標圧縮. comp: 圧縮後の配列, inve = i: 元の要素
def compress(a, idx=0):
sorted_a = sorted(list(set(a)))
inv = {e: i for i, e in enumerate(sorted_a, start=idx)}
cmp_a = [inve for e in a]
return cmp_a, inv
from atcoder.segtree import SegTree
INF = float('inf')
op, e = max, -INF # 区間演算が最大値のとき.
n = int(input())
a = int(input()) for _ in range(n)
a, _ = compress(a, idx=1) # 座標圧縮(1-index)
# dpi: 最後の要素が i であるLISの長さ
st = SegTree(op, e, -INF * (n + 1)) # dp = -INF * (n + 1)
st.set(0, 0) # dp0 = 0
for aa in a:
st.set(aa, st.prod(0, aa) + 1) # dpaa = max(dp0:aa) + 1
print(st.all_prod())
#DP #座標圧縮 #セグメント木