1 条题解

  • 0
    @ 2024-11-20 13:29:09

    ST表

    虽然ST表不是本题的唯一实现,但是静态RMQ问题ST表是最好写的。

    oi-wiki:ST 表(Sparse Table,稀疏表)是用于解决 可重复贡献问题 的数据结构

    O(nlogn)的预处理

    我们可以发现区间最大值是一个具有「可重复贡献」性质的问题。即使用来求解的预处理区间有重叠部分,只要这些区间的并是所求的区间,最终计算出的答案就是正确的。

    我们定义f[i][j]f[i][j]表示从第i个数起连续2j12^j-1个数中的最大值

    我们把f[i][j]f[i][j]平均分成两段(因为f[i][j]f[i][j]一定是偶数个数字),从 iii+2j11i+2^{j-1}-1 为一段,i+2j1i + 2 ^ {j - 1}i+2j1i + 2 ^ j - 1为一段(长度都为 2j12 ^ {j - 1} )。

    于是我们得到了状态转移方程 F[i][j]=maxF[i][j1],F[i+2j1][j1]F[i][j]=max(F[i][j-1], F[i + 2^{j-1}][j-1])

    如图:

    优秀的O(1)查询 qwqqwq

    我们思考如何查询 [l,r][l,r]

    可以用与预处理一样的方法

    我们依旧定义f[i][j]f[i][j]表示从第i个数起连续2j12^j-1个数中的最大值

    我们把它分成两部分:[l,l+2s1][l,l+2^s-1][r2s+1,r][r-2^s+1,r],其中 s=log2(rl+1)s=\left\lfloor\log_2(r-l+1)\right\rfloor。两部分的结果的最大值就是回答。

    log2x\log_2x可以用cmath的库函数,也可以线性预处理

    log2x\log_2xrl+1\left\lfloor r-l+1\right\rfloor显然llrr之间是有交集且不会超范围的。

    如图:

    ACcodeAC code

    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 100005
    #define maxm 17 //考虑题目取log2
    int fm[maxn][maxm],fn[maxn][maxm],logn[maxn];
    int n,m;
    void pre() {
    	logn[1]=0;
    	logn[2]=1;
    	for(int i=3; i<maxn; i++)
    		logn[i]=logn[i>>1]+1;
    }
    int read() {
    	int x=0,f=1;
    	char ch=getchar();
    	while (ch<'0'||ch>'9') {
    		if (ch=='-') f=-1;
    		ch=getchar();
    	}
    	while (ch>='0'&&ch<='9') {
    		x=x*10+ch-48;
    		ch=getchar();
    	}
    	return x*f;
    }//快速读入
    int x,y;
    int main() {
    	n=read(),m=read();
    	pre();
    	for(int i=1; i<=n; i++){
            fm[i][0]=read();
            fn[i][0]=fm[i][0];// 数据读入
        }
        for (int j = 1; j < maxm; j++)//动态规划预处理得到ST表
    		for (int i = 1; i + (1 << j) - 1 <= n; i++){
    			fm[i][j] = max(fm[i][j - 1], fm[i + (1 << (j - 1))][j - 1]);
                fn[i][j] = min(fn[i][j - 1], fn[i + (1 << (j - 1))][j - 1]);
        }
        for (int i = 1; i <= m; i++) {
    		int x = read(), y = read();
    		int s = logn[y - x + 1];//O(1)询问
            int ansm=max(fm[x][s], fm[y - (1 << s) + 1][s]);
            int ansn=min(fn[x][s], fn[y - (1 << s) + 1][s]);
    		printf("%d\n", ansm-ansn);
    	}
    	return 0;
    }
    
    • 1

    信息

    ID
    6910
    时间
    1000ms
    内存
    125MiB
    难度
    3
    标签
    递交数
    20
    已通过
    4
    上传者