【问题描述】
Wind 设计了很多机器人。但是它们都认为自己是最强的,于是,一场比赛开始了……
机器人们都想知道谁是最敏捷的,于是它们进行了如下一个比赛。首先,他们面前会有一排共 n个数,它们比赛看谁能最先把每连续 k个数中最大和最小值写下来,当然,这些机器人运算速度都很快,它们比赛的是谁写得快。
但是 Wind 也想知道答案,你能帮助他吗?
【输入格式】
第一行包含两个整数 n,k,含义见题目描述。
第二行包含 n个整数,表示数字序列。
【输出格式】
共 n−k+1行,第 i 行为第 i 至第 i+k−1 这 k个数中的最大和最小值。
【数据范围】
1≤k≤n≤10^5,
数列中的数均在 [−2^31,2^31−1]范围内。
【输入样例】
5 3
1 2 3 4 5
【输出样例】
3 1
4 2
5 3
【算法分析】
本题利用了ST算法求解。反映ST算法核心思想的示意图重绘于下:
ST算法详见:
https://blog.csdn.net/hnjzsyjyj/article/details/103429761
https://blog.csdn.net/hnjzsyjyj/article/details/120479214
【算法代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
const int maxm=20; //∵log(10^6)<20
int a[maxn];
int f[maxn][maxm]; //f[i][j]表示从i位起的2^j个数中的最大数
int f1[maxn][maxm]; //f1[i][j]表示从i位起的2^j个数中的最小数
int ansmax(int x,int y) {
int k=log2(y-x+1);
return max(f[x][k],f[y-(1<<k)+1][k]);
}
int ansmin(int x,int y) {
int k=log2(y-x+1);
return min(f1[x][k],f1[y-(1<<k)+1][k]);
}
int main() {
int n,m;
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++) {
scanf("%d",&a[i]); //数组a的下标从1开始
f[i][0]=a[i]; //f[i][0]表示[i,i]中的最大值,只能是a[i],故f[i][0]=a[i]
f1[i][0]=a[i]; //f1[i][0]表示[i,i]中的最小值,只能是a[i],故f1[i][0]=a[i]
}
for(int j=1; j<=log2(n); j++)
for(int i=1; i+(1<<j)-1<=n; i++) { //注意i的右端点为i+(1<<j)-1,不能越界
f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]); //预处理
f1[i][j]=min(f1[i][j-1],f1[i+(1<<(j-1))][j-1]);
}
for(int i=1; i<=n-m+1; i++) {
printf("%d %d\n",ansmax(i,i+m-1),ansmin(i,i+m-1));
}
return 0;
}
/*
in:
5 3
1 2 3 4 5
out:
3 1
4 2
5 3
*/
【参考文献】
https://www.acwing.com/problem/content/description/1273/
https://blog.csdn.net/weixin_44270812/article/details/103063804