P2880 [USACO07JAN]平衡的陣容Balanced Lineup 題解
阿新 • • 發佈:2021-12-23
P2880 [USACO07JAN]平衡的陣容Balanced Lineup 題解
這兩個區間。所以,通過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})
\]
瞎扯
剛看到這個題目的時候我就嚇著了:藍題?溜了溜了……但是還是好奇地點進去看了一下。看完題面之後,恕我冒昧說一句話,這題不應該是黃題嗎?怎麼會是藍題?簡直就是明顯(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]\)
其中\(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; }