1. 程式人生 > >算法學習——st表

算法學習——st表

合並 什麽 沒有 mes 怎麽 空格 mage info int

st表是一種基於倍增思想的DP。

用於求一個數列中的某個區間的最大/最小值。

用st[i][j]表示從第i個開始往後2^j個點,最大的是多少。

我們令k[i]表示2^i等於多少

那麽有轉移方程

st[i][j] = max(st[i][j - 1], st[i + k[i - 1]][j - 1]);

為什麽呢?

技術分享圖片

例如這幅圖,顯然黑色塊的答案可以由合並下面兩塊得到。

那如果查詢的時候不是2的整次冪怎麽辦?

這其實是沒有問題的,你可以觀察下圖……

技術分享圖片

因為小區間有重疊部分並不影響,因此完全可以用稍大一點的小區間湊出大區間。
預處理一點信息以快速查詢答案即可。

(早期代碼,沒有空格空行,略醜)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,m,s[100500],f[100500][18],p[100500];
 4 int Max(int a,int b)
 5 {
 6     if(a>b)return a;
 7     else return b;
 8 }
 9 int Min(int a,int b)
10 {
11     if(a<b)return a;
12     else return b;
13 }
14 void pre()
15 { 16 int i,a,key=1; 17 for(i=1;i<=n;i++) 18 { 19 if(i==(key<<1))p[i]=p[i-1]+1,key<<=1; 20 else p[i]=p[i-1]; 21 scanf("%d",&a); 22 f[i][0]=a; 23 } 24 for(int j=1;j<=17;j++) 25 for(i=1;i<=n;i++) 26 {
27 f[i][j]=Max(f[i][j-1],f[Min(i+(1<<(j-1)),n)][j-1]); 28 } 29 } 30 int main() 31 { 32 int i,a,b,k; 33 scanf("%d%d",&n,&m); 34 pre(); 35 for(i=1;i<=m;i++) 36 { 37 scanf("%d%d",&a,&b); 38 k=p[b-a+1]; 39 printf("%d\n",Max(f[a][k],f[b-(1<<k)+1][k])); 40 } 41 return 0; 42 }

算法學習——st表