Spring Boot日誌記錄
阿新 • • 發佈:2021-06-10
請看一個題
設有一個長度為N的陣列arr,求 0<=a<=b<N a~b 的最大值(或最小值) 會求很多次
最簡單的演算法就是弄一個二維陣列,先算好 a~b 的 最大最小值。但是這樣太浪費記憶體了。
RMQ 演算法 就是為了巧妙地運用2的冪數/對數 解決這個問題的。
設 dp[i][j] 為 以i為起點,1<<j長度的,最大值。
這樣,如果需要求 a~b 的最大值,則只需 求 max(dp[a][某個長度],dp[b-(1<<某個長度)+1][某個長度]
其中 某個長度 = log2(b-a+1)
void query(int a,int b,int &maxV){ int r = mlog2(b-a+1); maxV = max(dpMax[a][r],dpMax[b-(1<<r)+1][r]); }
而初始化dp 也是以同樣類似的思路去解決。
附 poj3264 ac程式碼
#include <iostream> #include <cassert> #include <vector> #include <queue> #include <string> #include <cstring> #include <cmath> #include <climits> #include <functional> #include <list> #include <cstdlib> #include <set> #include <stack> #include <map> #include <algorithm> using namespace std; #define MAXN 50005 int h[MAXN]; int dpMin[MAXN][16]; int dpMax[MAXN][16]; int mlog2(int x) { double xx = x; double v1 = log(xx); double v2 = log(2.0); return v1/v2; } void genDP(int len){ for(int i=0;i<len;i++){ dpMax[i][0] = h[i]; dpMin[i][0] = h[i]; } for(int j=1;(1<<j)<len;j++){ for( int i=0;i+(1<<j)-1<len;i++ ){ int r = i+(1<<(j-1)); dpMax[i][j] = max(dpMax[i][j-1],dpMax[r][j-1]); dpMin[i][j] = min(dpMin[i][j-1],dpMin[r][j-1]); } } } void query(int a,int b,int &maxV,int &minV){ int r = mlog2(b-a+1); maxV = max(dpMax[a][r],dpMax[b-(1<<r)+1][r]); minV = min(dpMin[a][r],dpMin[b-(1<<r)+1][r]); } int main(){ int N,Q; int t; scanf("%d%d",&N,&Q); for( int i=0;i<N;i++ ){ scanf("%d",&t); h[i] = t; } genDP(N); int a,b; int maxV,minV; for( int i=0;i<Q;i++ ){ scanf("%d%d",&a,&b); if ( a==b ){ printf("0\n"); }else{ query(a-1,b-1,maxV,minV); printf("%d\n",maxV-minV); } } return 0; }