第14回ブルーブリッジカップ第3回シミュレーション - リプレイ

3 番目のシミュレーションは、最初の 2 つのシミュレーション (水のバッチ) の一貫したスタイルを継続しました。難しくはありませんが、まだ大丈夫な質問がいくつかあります。前に学んだ知識を復習するために最後の質問を説明しましょう。

問題の説明:

Xiaolan にはシーケンス a[1]、a[2]、...、a[n] があります。正の整数 k が与えられた場合、1 から n までの各シリアル番号 ia[ik] について、2k+1 個の数値のうちの a[i-k+1]...a[i+K] の最小値はいくらですか
? 添字が 1 から n の範囲を超える場合、その数値は存在せず、最小値を計算するときに存在する値のみが使用されます。

入力形式:

入力の最初の行には整数 n が含まれています。2 行目には、それぞれ a[1]、a[2]、...、a[n] を表す n 個の整数が含まれています。3 行目には整数 k が含まれています

出力フォーマット:

各フォント サイズで取得された最小値をそれぞれ表す n 個の整数を含む行を出力します。

入力例:

5
5 2 7 4 3
1

出力例:

2 2 2 3 3

評価ユースケースの規模と合意

評価ケースの 30% では、1 <= n <= 1000、1 <= a[i] <= 1000。
評価ケースの 50% では、1 <= n <= 10000、1 <= a[i] <= 10000。
すべての評価ケースで、1 <= n <= 1000000、1 <= a[i] <= 1000000

アイデア 1:ツリー配列

まず、ツリー配列について説明します。
まず質問の意味を掘り出し、シーケンスを走査し、走査された要素の範囲の最大値を見つけます。走査が進むにつれて、区間内の要素が変化します。つまり、要素を変更する必要があります。区間内の最大の値については、バイナリ メソッドを使用して見つけることができます。
具体的な方法は、現在トラバースされている要素の特定のサイズ範囲 (2k + 1) でレコード値のツリー状配列を維持することです。各走査では二分探索を使用して、この間隔の最小値を見つけます。

コード

N = 100010

tr = [0] * N
a = [0] * N

def lowbit(x) : return x & -x

def add(x, c) :
    i = x
    while i <= n :
        tr[i] += c
        i += lowbit(i)

def ask(x) :
    res = 0
    i = x
    while i :
        res += tr[i]
        i -= lowbit(i)
    return res

def init() : # 初始化,将第一个元素右边的m个元素初始化树状数组
    for i in range(1, m + 1) :
        add(a[i], 1)

n = int(input())
a[1 : n + 1] = list(map(int, input().split()))
maxn = max(a[1 : n + 1])
m = int(input())
init()
for i in range(1, n + 1) : 
    if i + m <= n : # 随着区间的挪动添加元素
        add(a[i + m], 1)
    if i - m - 1 >= 1 : # # 随着区间的挪动删除元素
        add(a[i - m - 1], -1)
    l, r = 0, maxn # 二分查找,右半段查找最小值
    while l < r :
        mid = (l + r) >> 1
        if ask(mid) >= 1 :
            r = mid
        else :
            l = mid + 1
    print(l, end = " ")

アイデア 2:スライディング ウィンドウ

上記の説明から、それが引き違い窓であることは明らかです。
ウィンドウ サイズ 2*k+1 で単調減少するキューを維持するだけです。

コード

N = 1000010

a = [0] * N
q = [0] * N

n = int(input())

a[1 : n + 1] = list(map(int, input().split()))

m = int(input())

hh, tt = 0, -1

def init() : # 初始化,将前m个进队列,这时只需要保持单调性即可
    global tt
    for i in range(1, m + 1) :
        while hh <= tt and a[q[tt]] >= a[i] :
            tt -= 1
        tt += 1
        q[tt] = i
init()

for i in range(m + 1, n + m + 1) :
    while hh <= tt and i - q[hh] + 1 > 2 * m + 1 :
        hh -= 1
    if i <= n : # 防止序列越界
        while hh <= tt and a[q[tt]] >= a[i] :
            tt -= 1
        tt += 1
        q[tt] = i
    print(a[q[hh]], end = " ")

アイデア 3:線分ツリー

考え方はツリー配列や範囲クエリと同じです。

N = 1000010

class Tree :
    def __init__(self) :
        self.l = 0
        self.r = 0
        self.v = 0

tr = [Tree() for _ in range(N * 4)]
a = [0] * N

def pushup(u) :
    tr[u].v = min(tr[u << 1].v, tr[u << 1 | 1].v)

def build(u, l, r) :
    tr[u].l, tr[u].r = l, r
    if l == r :
        tr[u].v = a[l]
        return
    mid = l + r >> 1
    build(u << 1, l, mid)
    build(u << 1 | 1, mid + 1, r)
    pushup(u)

def query(u, l, r) :
    if l <= tr[u].l and tr[u].r <= r :
        return tr[u].v
    res = 10000010
    mid = tr[u].l + tr[u].r >> 1
    if l <= mid :
        res = query(u << 1, l, r)
    if r > mid :
        res = min(res, query(u << 1 | 1, l, r))
    return res

n = int(input())

a[1 : n + 1] = list(map(int, input().split()))

m = int(input())
build(1, 1, n)

for i in range(1, n + 1) :
    l, r = max(1, i - m), min(i + m, n)
    print(query(1, l, r), end = " ")

アイデア 4: RMQ

from math import log

N = 1000010

a = [0] * N
f = [[1000010] * 25 for _ in range(N)]

n = int(input())

a[1 : n + 1] = list(map(int, input().split()))
m = int(input())

def init() : # 预处理st表
    for i in range(1, n + 1) :
        f[i][0] = a[i]
    k = int(log(n, 2)) + 1
    for length in range(1, k) :
        for l in range(1, n + 1) :
            r = l + (1 << length) - 1
            if r > n : break
            f[l][length] = min(f[l][length - 1], f[l + (1 << (length - 1))][length - 1])

def query(l, r) :
    k = int(log(r - l + 1, 2))
    return min(f[l][k], f[r - (1 << k) + 1][k])

init()

for i in range(1, n + 1) :
    l, r = max(1, i - m), min(i + m, n)
    print(query(l, r), end = " ")

おすすめ

転載: blog.csdn.net/qq_57150526/article/details/129345922