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;
}
上一篇:mysql null不参与计算


下一篇:MySQL 数据类型