1. 程式人生 > 資訊 >哥倫比亞進口:雀巢黑咖啡 22.8 元速囤(立減 56 元)

哥倫比亞進口:雀巢黑咖啡 22.8 元速囤(立減 56 元)

請看一個題
設有一個長度為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;
}