最敏捷的机器人 ← ST算法 倍增

【问题描述】
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
 

猜你喜欢

转载自blog.csdn.net/hnjzsyjyj/article/details/120495668
今日推荐