演算法 日更 第十九期 動態規劃 RMQ問題

2022-07-12 11:15:12 字數 3758 閱讀 9426

▎前言

首先先來說一下rmb是什麼,當然是人民幣啦。

今天我們要學的這個東西不一般,叫做rmq問題,那麼它和rmb有什麼關係呢?待小編細細說來。

▎前置技能:動態規劃

不會的同志請戳這裡迅速了解動態規劃。

▎rmq問題是什麼

☞『定義』

☞『問題解決:模擬演算法』

rmq只是一類這樣的問題,卻不是一門演算法。

既然是問題,那麼我們就應該解決,但是怎麼解決,怎樣解決,一切先從模擬演算法(直白一點叫暴力)說起。

先來想想模擬演算法怎麼解決,當然是給定區間後直接遍歷,尋找最大/最小值唄。但是別忘了,這種題多次詢問,一直遍歷對於資料規模大的題簡直是杯水車薪。

此時,不得不請出動態規劃。

☞『問題解決:動態規劃』

我們為什麼使用動態規劃呢?先來思考這個問題:為什麼暴力不能滿足需求。

你肯定會說:這還不簡單,暴力慢唄。

但是暴力究竟慢在了**?暴力慢在了沒有完全利用好整個大區間,很多東西都在重複遍歷。

那麼什麼東西能很好的利用大區間呢?我們就會自然的想到了動態規劃(感覺屬於區間動態規劃)。

既然多次詢問,那麼就變向的告訴了我們一定要預處理,這裡我們的動態規劃可以o(n log n)預處理,然後o(1)查詢。

先來思考怎麼設計狀態,最開始小編是這樣想的,既然是區間型動態規劃類問題,那麼就讓f[i][j]表示i~j區間內的最大/最小數吧,(以最大數為例)狀態轉移方程自然就是f[i][j]=max(f[i][k],f[k+1][j])。(k為隨機乙個i~j區間的陣列下標,不過小編更喜歡取中點)

後來發現一本通提高篇上的設計狀態更好,更快捷,我設計的太慢了。一本通提高篇上是這樣處理的:f[i][j]表示i~2j-1區間內的最大/最小數,那麼我們可以仿照之前我的想法,分一半,就是這樣的:

從區間初始和結束位置改成動態規劃的形式後就是這樣的:f[i][j-1]和f[i+2j-1][j-1],有時候奇數和偶數是不一樣的,所以小編的圖可能對這兩個式子來說不太標準。

那麼我們要求的最大最小值就很簡單了。

但是問題又來了,我們如何面對詢問呢?

我們可以以二為底,將這個區間內數字的個數次方(冪的逆運算)為界,進行比較兩個區間大小,**一下:

那麼我們就只要比較出兩個區間中的最大最小值即可。兩個區間改成動態規劃形式就是f[x][log[d]],f[y-(1好了,問題又來了,log怎麼處理,我們先來看一下前10個數的log處理情況:

經過專業調查和探尋後,就會發現log[i]=log[i/2]+1的規律,因此我們可以預處理出log的值。

☞『這麼快的演算法,為什麼還需要其他演算法呢?』

其實這個問題正是這個演算法的弊端,因為不能支援期間修改一些數的值。

而線段樹,樹狀陣列正巧妙的解決了這一弊端。

▎實戰演練:洛谷p1816 忠誠(模板題)

廢話不多說,直接上題:

老管家是乙個聰明能幹的人。他為財主工作了整整10年,財主為了讓自已賬目更加清楚。要求管家每天記k次賬,由於管家聰明能幹,因而管家總是讓財主十分滿意。但是由於一些人的挑撥,財主還是對管家產生了懷疑。於是他決定用一種特別的方法來判斷管家的忠誠,他把每次的賬目按1,2,3…編號,然後不定時的問管家問題,問題是這樣的:在a到b號賬中最少的一筆是多少?為了讓管家沒時間作假他總是一次問多個問題。

輸入格式:

輸入中第一行有兩個數m,n表示有m(m<=100000)筆賬,n表示有n個問題,n<=100000。

第二行為m個數,分別是賬目的錢數

後面n行分別是n個問題,每行有2個數字說明開始結束的賬目編號。

輸出格式:

輸出檔案中為每個問題的答案。具體檢視樣例。

輸入樣例#1: 複製

10 3

1 2 3 4 5 6 7 8 9 10

2 73 9

1 10

輸出樣例#1: 複製

2 3 1
這道題相當好做,就是模板題,所以就不解釋了,直接上**:

1 #include2

using

namespace

std;

3int m,n,a[100000],f[100000][100],x,y,log[100000];4

intmain()512

for(int j=1;j<=16;j++)

13for(int i=1;i+(1

<1

<=m;i++)

14 f[i][j]=min(f[i][j-1],f[i+(1

<

]);15 log[1]=0;16

for(int i=2;i<=100000;i++)

17 log[i]=log[i/2]+1;18

for(int i=1;i<=n;i++)

1924

return0;

25 }

▎實戰演練:一本通1541:【例 1】數列區間最大值(模板題)

廢話不多說,直接上題:

時間限制: 1000 ms         記憶體限制: 524288 kb

提交數: 638     通過數: 224 

輸入一串數字,給你 m

'>

m 個詢問,每次詢問就給你兩個數字 x,y

'>

x,y,要求你說出 x

'>

x 到 y

'>

y 這段區間內的最大數。

第一行兩個整數 n,m

'>

n,m 表示數字的個數和要詢問的次數;

接下來一行為 n

'>

n 個數;

接下來 m

'>

m 行,每行都有兩個整數 x,y

'>

x,y。

輸出共 m

'>

m 行,每行輸出乙個數。

10 2

3 2 4 5 6 8 1 2 9 7

1 43 8

5

8

對於全部資料,1≤n

≤105,

1≤m≤

106,1

≤x≤y

≤n'>1≤n≤105

,1≤m≤106

,1≤x≤y≤n

。數字不超過 c/c

++'>c/c++

的 in

t'>

int 範圍。

無這道題只要把忠誠的**改成max就可以了(還稍微有點其他細節),注意會卡常數,不能用cin和cout。**如下:

1 #include2 #include3

using

namespace

std;

4int m,n,a[1000000],f[1000000][100],x,y,log[1000000];5

intmain()613

for(int j=1;j<=18;j++)

14for(int i=1;i+(1

<1

<=m;i++)

15 f[i][j]=max(f[i][j-1],f[i+(1

<

]);16 log[1]=0;17

for(int i=2;i<=m;i++)

18 log[i]=log[i>>1]+1;19

for(int i=1;i<=n;i++)

2025

return0;

26 }

極樂技術週報 第十九期

極樂技術週報 第十九期 為什麼程式設計師總是搞混萬聖節和聖誕節?因為.oct 31 dec 25。驗證碼就如同馬奇諾防線一樣,阻擋了爬蟲工程師的正面進攻。隨著爬蟲和反爬蟲雙方圍繞驗證碼的不斷較量,最終導致了驗證碼識別難度的不斷上公升。鏈結位址 一直以來,使用純 css 實現波浪效果都是十分困難的。因...

學習日誌第十九日

學習日誌 姓名 陳長穩 日期 7.27 今日學習任務 今日主要運用昨日講的知識點,點亮開發板上的四個燈。今日任務完成情況 基本完成了nvic中斷基礎介紹,除錯功能printf功能配置介紹以及exti基礎及按鍵實現的學習,並用中斷延時程式完成了控制乙個燈閃爍,以及通過按鍵點亮led燈。今日開發中出現的...

大話IT第十九期 戴爾收購物件大猜想

讓人唏噓的不只是娛樂圈的分分合合,it界的分分合合也不遜色 為什麼這麼說呢?大家先來看看這段戴爾 emc版的 十年 或許就明白了 十年 獻給dell emc舉案齊眉的過往 作詞 戴爾 作曲 圖斯 表演者 戴爾 圖斯 十年之前,我不轉銷你你不收購我 我們還是一樣陪在企業級客戶左右 走過擁擠的華爾街頭 ...