用st表來解決rmq問題。
表示同時培訓學的st表,然後我就忘得差不多了,在這裡推薦一篇blog
大佬cym的
自己再**一篇
舉例:給出一陣列a[0~5] = ,則區間[2,5]之間的最值為1。
(1)離線預處理:運用dp思想,用於求解區間最值,並儲存到乙個二維陣列中。
具體解釋:
(1)離線預處理:
st演算法使用dp思想求解區間最值,貌似屬於區間動態規劃,不過區間在增加時,每次並不是增加乙個長度,而是使用倍增的思想,每次增加2^i個長度。
使用f[i,j]表示以i為起點,區間長度為2^j的區間最值,此時區間為[i,i + 2^j - 1]。
比如,f[0,2]表示區間[0,3]的最小值,即等於4,f[2,2]表示區間[2,5]的最小值,即等於1。
在求解f[i,j]時,st演算法是先對長度為2^j的區間[i,i + 2^j - 1]分成兩等份,每份長度均為2^(j - 1)。之後在分別求解這兩個區間的最值f[i,j - 1]和f[i + 2^(j - 1),j - 1]。,最後在結合這兩個區間的最值,求出整個區間的最值。特殊情況,當j = 0時,區間長度等於1,即區間中只有乙個元素,此時f[i,0]應等於每乙個元素的值。
舉例:要求解f[1,2]的值,即求解區間[1,4] = 的最小值,此時需要把這個區間分成兩個等長的區間,即為[1,2]和[3,4],之後分別求解這兩個區間的最小值。此時這兩個區間最小值分別對應著f[1,1] 和 f[3,1]的值。
狀態轉移方程是 f[i,j] = min(f[i,j - 1],f[i + 2^(j - 1),j - 1])
初始狀態為:f[i,0] = a[i]。
在根據狀態轉移方程遞推時,是對每一元素,先求區間長度為1的區間最值,之後再求區間長度為2的區間最值,之後再求區間長度為4的區間最值….,最後,對每乙個元素,在求解區間長度為log2^n的區間最值後,演算法結束,其中n表示元素個數。
即:先求f[0][1],f[1][1],f[2][1],f[3][1],,,f[n][1],再求.f[0][2],f[1][2],f[2][2],f[3][2],,,f[m][2],… 。
在預處理期間,每乙個狀態對應的區間長度都為2^i。由於給出的待查詢區間長度不一定恰好為2^i,因此我們應對待查詢的區間進行處理。
這裡我們把待查詢的區間分成兩個小區間,這兩個小區間滿足兩個條件:(1)這兩個小區間要能覆蓋整個區間(2)為了利用預處理的結果,要求小區間長度相等且都為2^i。注意兩個小區間可能重疊。
如:待查詢的區間為[3,11],先盡量等分兩個區間,則先設定為[3,7]和[8,11]。之後再擴大這兩個區間,讓其長度都等於為2^i。剛劃分的兩個區間長度分別為5和4,之後繼續增加區間長度,直到其成為2^i。此時滿足兩個條件的最小區間長度為8,此時i = 3。
在程式計算求解區間長度時,並沒有那麼麻煩,我們可以直接得到i,即等於直接對區間長度取以2為底的對數。這裡,對於區間[3,11],其分解的區間長度為int(log(11 - 3 + 1)) = 3,這裡log是以2為底的。
根據上述思想,可以把待查詢區間[x,y]分成兩個小區間[x,x + 2^i - 1] 和 [y - 2^i + 1,y] ,其又分別對應著f[x,i]和f[y - 2^i + 1,i],此時為了求解整個區間的最小值,我們只需求這兩個值得最小值即可,此時複雜度是o(1)。
**(
1 #include 2 #include 3using
namespace
std;
4int
const maxn = 1000000;5
int st[maxn][20
], a[maxn], ans[maxn];
6int
n, m, left, right, j, i;
7int
main()815
16for(j = 1; (1
<)
17for(i = 1; i <= n-(1
<1; i++)
18 st[i][j] = min(st[i][j-1] , st[i+( 1
<<(j-1) )][j-1
]);19
20for(i = 1; i <= m; i++)
2127
28for(i = 1; i <= m; i++)
29 printf("
%d "
,ans[i]);
30return0;
31 }
洛谷P1816 忠誠
老管家是乙個聰明能幹的人。他為財主工作了整整10年,財主為了讓自已賬目更加清楚。要求管家每天記k次賬,由於管家聰明能幹,因而管家總是讓財主十分滿意。但是由於一些人的挑撥,財主還是對管家產生了懷疑。於是他決定用一種特別的方法來判斷管家的忠誠,他把每次的賬目按1,2,3 編號,然後不定時的問管家問題,問...
洛谷P1816 忠誠 分塊
分塊真的是很暴力呀 暴力查詢左端,暴力查詢又端點,中間整體部分直接 o 1 求出。注意程式設計細節 belong i i 1 block 1 這樣可以保證序列被分成這樣的 code include include include includeusing namespace std const in...
倍增 rmq 忠誠 洛谷P1816
老管家是乙個聰明能幹的人。他為財主工作了整整10年,財主為了讓自已賬目更加清楚。要求管家每天記k次賬,由於管家聰明能幹,因而管家總是讓財主十分滿意。但是由於一些人的挑撥,財主還是對管家產生了懷疑。於是他決定用一種特別的方法來判斷管家的忠誠,他把每次的賬目按1,2,3 編號,然後不定時的問管家問題,問...