1. 程式人生 > 其它 >P2880 [USACO07JAN]平衡的陣容Balanced Lineup 題解

P2880 [USACO07JAN]平衡的陣容Balanced Lineup 題解

P2880 [USACO07JAN]平衡的陣容Balanced Lineup 題解

瞎扯

剛看到這個題目的時候我就嚇著了:藍題?溜了溜了……但是還是好奇地點進去看了一下。看完題面之後,恕我冒昧說一句話,這題不應該是黃題嗎?怎麼會是藍題?簡直就是明顯(luo)到不能再明顯(luo)的RMQ問題。

正題

所謂RMQ問題,就是找一個序列某段區間當中,最大或最小的數是多少。而解決它的一種工具就是ST表

我們可以假設\(f_{i,j}\)為區間\([i,i+2^j-1]\)內的最大或最小值。然後把它從中間分開,就可以看到分成了\([i,i+2^{j-1}]\)\([i+2^{j-1},i+2^{j-1}+2^{j-1}-1]\rightarrow[i+2^{j-1},i+2^j-1]\)

這兩個區間。所以,通過DP我們可以得出下面兩個方程:

\[f1_{i,j}=\max(f1_{i,j-1},f1_{i+2^j-1,j-1}) \]\[f2_{i,j}=\min(f2_{i,j-1},f2_{i+2^j-1,j-1}) \]

其中\(f1\)陣列求的是區間內最大值,\(f2\)陣列求的是區間內最小值。

本題的目標是要求\(\max(f1_{x,k},f1_{y-2^k+1,k})-min(f2_{x,k},f2_{y-2^k+1,k})\),雖然區間\([x,x+2^k-1]\)\([y-2^k+1,y]\)這兩個區間有交集,但並不影響求最值。這就是ST演算法的優勢。

其他的內容實現就靠大家了,本人的程式碼僅供參考:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;

int f1[100007][21], f2[100007][21], n, m, log[100007], x, y;

inline int read() {
	int f = 1, x = 0;
	char c = getchar();
	while(c < '0' || c > '9') {
		if(c == '-')	f = -1;
		c = getchar();
	}
	while(c >= '0' && c <= '9') {
		x = x * 10 + c - '0';
		c = getchar();
	}
	return x * f;
}
void pre() {
	for(int j = 1; j <= 20; ++j)
		for(int i = 1; i + (1 << j) - 1 <= n; ++i)
			f1[i][j] = max(f1[i][j - 1], f1[i + (1 << (j - 1))][j - 1]), f2[i][j] = min(f2[i][j - 1], f2[i + (1 << (j - 1))][j - 1]);
}

int main() {
	log[0] = -1;
	n = read(), m = read();
	for(int i = 1; i <= n; ++i) {
		f1[i][0] =  read();
		f2[i][0] = f1[i][0];
		log[i] = log[i >> 1] + 1;
	}
	pre();
	for(int i = 1; i <= m; ++i) {
		x = read(), y = read();
		int k = log[y - x + 1];
		printf("%d\n", max(f1[x][k], f1[y - (1 << k) + 1][k]) - min(f2[x][k], f2[y - (1 << k) + 1][k]));
	}
	return 0;
}