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;
}
标签:f1,f2,int,题解,区间,100007,P2880,Balanced,include 来源: https://www.cnblogs.com/Eason-AC/p/15725218.html