鱼C论坛

 找回密码
 立即注册
查看: 2479|回复: 27

[已解决]求助洛谷P2880!

[复制链接]
发表于 2023-8-19 10:58:47 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
我的代码:

  1. #include <bits/stdc++.h>
  2. using namespace std;

  3. int n, a[50010], q, l, r, zuida = -1, zuixiao = 1145141919;

  4. int main() {
  5.     cin >> n >> q;
  6.     for (int i = 1; i <= n; i++) {
  7.         cin >> a[i];
  8.     }
  9.     for (int i = 1; i <= q; i++) {
  10.         cin >> l >> r;
  11.         zuida = -1, zuixiao = 1145141919;
  12.         for (int j = l; j <= r; j++) {
  13.             zuida = max(zuida, a[j]);
  14.             zuixiao = min(zuixiao, a[j]);
  15.         }
  16.         cout << zuida - zuixiao << endl;
  17.     }

  18.     return 0;
  19. }
复制代码


TLE QAQ,要如何优化呢?

题解都说用ST表,蒟蒻不会啊QAQ

有没有大佬解释一下ST表要怎么用啊


最佳答案
2023-8-19 11:36:56
本帖最后由 zhangjinxuan 于 2023-8-26 19:52 编辑

st表学的不精,待会儿给你ST板子。

ST大致思路好像就是,定义 f[ i][ j] 为 i ~ i+2^j-1 这个区间的最小值(其他运算也可以,但是有限制),然后求 i j 区间最小值就分两段(两段必须覆盖整个区间,可以重叠)求值即可。

这里的运算(假定运算符为@)必须让 A@A =A一定成立,加法不行,最大值可以,或运算,与运算也可以。
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2023-8-19 11:00:09 | 显示全部楼层
ST表是一种用于解决区间最值问题的数据结构。它可以在O(nlogn)的预处理时间内,回答任意区间的最值查询。

在你的代码中,你使用了两个循环来遍历查询区间内的元素,这样的时间复杂度是O(q*(r-l+1)),当数据规模较大时会超时。所以可以使用ST表来优化。

ST表的构建过程如下:
1. 首先,我们需要创建一个二维数组dp,其中dp[ i][j]表示从位置i开始,长度为2^j的区间内的最大值(或最小值,根据问题要求而定)。
2. 初始化dp数组的第一列,即dp[ i][0] = a[ i]。
3. 然后,根据以下递推关系计算dp数组的其他列:
   · 如果2^j > n-i+1,则dp[ i][j] = dp[ i][j-1]。
   · 否则,dp[ i][j] = max(dp[ i][j-1], dp[i+2^(j-1)][j-1])。

构建完成后,我们可以通过查询dp数组来回答任意区间的最值查询。具体步骤如下:
1. 计算区间长度len = r - l + 1。
2. 找到最大的k,使得2^k <= len。
3. 查询结果为max(dp[l][k], dp[r-2^k+1][k])。

下面是应用ST表优化后的代码:

  1. #include <bits/stdc++.h>
  2. using namespace std;

  3. const int MAXN = 50010;
  4. const int MAXLOG = 20;

  5. int n, a[MAXN], q, l, r;
  6. int dp[MAXN][MAXLOG];

  7. int main() {
  8.     cin >> n >> q;
  9.     for (int i = 1; i <= n; i++) {
  10.         cin >> a[ i];
  11.     }

  12.     // 构建ST表
  13.     for (int i = 1; i <= n; i++) {
  14.         dp[ i][0] = a[ i];
  15.     }
  16.     for (int j = 1; (1 << j) <= n; j++) {
  17.         for (int i = 1; i + (1 << j) - 1 <= n; i++) {
  18.             dp[ i][j] = max(dp[ i][j-1], dp[i+(1<<(j-1))][j-1]);
  19.         }
  20.     }

  21.     // 查询区间最值
  22.     for (int i = 1; i <= q; i++) {
  23.         cin >> l >> r;
  24.         int len = r - l + 1;
  25.         int k = log2(len);
  26.         int ans = max(dp[l][k], dp[r-(1<<k)+1][k]);
  27.         cout << ans << endl;
  28.     }

  29.     return 0;
  30. }
复制代码


这样,你的代码就能通过洛谷P2880的测试了。希望能帮到你!
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-19 11:00:13 | 显示全部楼层
洛谷 P2880 题目是求区间最大值与最小值的差的最小值。你提供的代码使用了暴力法,对每个查询的区间进行遍历,时间复杂度较高。

ST 表(Sparse Table)是一种用于快速求解区间最大值或最小值的数据结构,利用动态规划的思想,在预处理阶段计算出所有可能区间的最大值或最小值,并存储在一个二维数组中。这样,在查询时可以通过查表从中取出结果,达到快速查询的目的。

以下是使用 ST 表来优化的示例代码:

  1. #include <bits/stdc++.h>
  2. using namespace std;

  3. const int MAXN = 50010;
  4. const int K = 20;  // ST 表的最大层数

  5. int n, a[MAXN], st[MAXN][K+1];

  6. // 预处理 ST 表
  7. void initST() {
  8.     for (int i = 1; i <= n; i++) {
  9.         st[ i][0] = a[ i];
  10.     }
  11.     for (int j = 1; j <= K; j++) {
  12.         for (int i = 1; i + (1 << j) - 1 <= n; i++) {
  13.             st[ i][j] = max(st[ i][j-1], st[i + (1 << (j-1))][j-1]);  // 可根据题意改变操作符
  14.         }
  15.     }
  16. }

  17. // 查询区间 [l, r] 的最大值
  18. int queryST(int l, int r) {
  19.     int k = log2(r - l + 1);  // 通过对数函数求出区间长度对应 ST 表的层数
  20.     return max(st[l][k], st[r - (1 << k) + 1][k]);  // 可根据题意改变操作符
  21. }

  22. int main() {
  23.     cin >> n;
  24.     for (int i = 1; i <= n; i++) {
  25.         cin >> a[ i];
  26.     }
  27.     initST();  // 预处理 ST 表

  28.     int q, l, r;
  29.     cin >> q;
  30.     while (q--) {
  31.         cin >> l >> r;
  32.         int zuida = queryST(l, r);
  33.         int zuixiao = *min_element(a+l, a+r+1);
  34.         cout << zuida - zuixiao << endl;
  35.     }

  36.     return 0;
  37. }
复制代码


这段代码使用了 ST 表来预处理数组,通过动态规划计算出所有区间的最大值,然后在查询时快速取出结果。注意,这里用到了 max() 函数和 min_element() 函数,可以根据题目要求进行修改。

希望这个示例能够帮助你理解 ST 表的使用方法。如果还有其他问题,请随时提问。
如果问题已经解决,请设置最佳答案
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-8-19 11:23:12 | 显示全部楼层
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-19 11:36:56 From FishC Mobile | 显示全部楼层    本楼为最佳答案   
本帖最后由 zhangjinxuan 于 2023-8-26 19:52 编辑

st表学的不精,待会儿给你ST板子。

ST大致思路好像就是,定义 f[ i][ j] 为 i ~ i+2^j-1 这个区间的最小值(其他运算也可以,但是有限制),然后求 i j 区间最小值就分两段(两段必须覆盖整个区间,可以重叠)求值即可。

这里的运算(假定运算符为@)必须让 A@A =A一定成立,加法不行,最大值可以,或运算,与运算也可以。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-19 11:41:38 | 显示全部楼层
st 求解 rmq 问题:

  1. int main(){
  2.     scanf("%d%d", &n, &q);
  3.     for (int i = 1; i <= n; i++) {
  4.         输入  ai
  5.         f[0][i] = a[i];
  6.     }
  7.     for (int j = 1; j <= 20; ++j) {
  8.                 for (int i = 1; i + (1 << j) - 1 <= n; ++i) {
  9.                         f[j][i] = max(f[j - 1][i], f[j - 1][i + (1 << (j - 1))]);
  10.                 }
  11.         }
  12.     for (int i = 1; i <= q; i++) {
  13.         读入 l,r
  14.         if (l > r) swap(l, r);
  15.         unsigned int x = __lg(r - l + 1);
  16.         输出 max(f[x][l], f[x][r - (1 << x) + 1]);
  17.     }
  18. }
复制代码
也不需要倍增呃
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-19 12:23:09 | 显示全部楼层
zhangjinxuan 发表于 2023-8-19 11:36
st表学的不精,待会儿给你ST板子。

ST大致思路好像就是,定义 f[ i][ j] 为 i ~ i+2^j-1 这个区间的最小 ...

nb
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-19 12:26:15 | 显示全部楼层
zhangjinxuan 发表于 2023-8-19 11:41
st 求解 rmq 问题:
也不需要倍增呃

%%%%
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-19 12:27:55 | 显示全部楼层
这道题本来是道蓝题(提高+/省选-),因为可以用ST表降黄了,神奇

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-8-19 12:49:47 | 显示全部楼层
sfqxx 发表于 2023-8-19 12:27
这道题本来是道蓝题(提高+/省选-),因为可以用ST表降黄了,神奇

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-19 17:25:57 | 显示全部楼层
不会?没关系的,查看题解抄下来,还送棕名认证!
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-8-19 17:44:33 | 显示全部楼层
高山 发表于 2023-8-19 17:25
不会?没关系的,查看题解抄下来,还送棕名认证!

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-19 17:45:59 | 显示全部楼层

赶紧做起来吧,越快越好,记得发帖@管理员,我正准备努力成为一个呢(你知道我 条件远远不够,蓝勾红名一个都没打成,之前抄题解还没被人发现
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-8-19 17:52:25 | 显示全部楼层
高山 发表于 2023-8-19 17:45
赶紧做起来吧,越快越好,记得发帖@管理员,我正准备努力成为一个呢(你知道我 条件远远不够,蓝勾红名一 ...

你是不是神经?
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-19 17:54:02 | 显示全部楼层

神经元处理系统?
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-20 13:24:07 | 显示全部楼层
  1. #include <bits/stdc++.h>
  2. using namespace std;

  3. const int maxn = 50010;
  4. int n, h[maxn], q, l, r, log_2[maxn], rmax[maxn][18], rmin[maxn][18];

  5. void init() {
  6.     for (int i = 1; i <= n; i++) rmax[i][0] = rmin[i][0] = h[i];
  7.     for (int j = 1; (1 << j) <= n; j++)
  8.         for (int i = 1; i <= n - (1 << j) + 1; i++) {
  9.             rmax[i][j] = max(rmax[i][j - 1], rmax[i + (1 << j - 1)][j - 1]);
  10.             rmin[i][j] = min(rmin[i][j - 1], rmin[i + (1 << j - 1)][j - 1]);
  11.         }
  12. }

  13. int mymax(int l, int r) {
  14.     int x = log_2[r - l + 1];
  15.     return max(rmax[l][x], rmax[r - (1 << x) + 1][x]);
  16. }

  17. int mymin(int l, int r) {
  18.     int x = log_2[r - l + 1];
  19.     return min(rmin[l][x], rmin[r - (1 << x) + 1][x]);
  20. }

  21. int main() {
  22.     cin >> n >> q;
  23.     for (int i = 1; i <= n; i++) cin >> h[i];
  24.     for (int i = 2; i <= n; i++) log_2[i] = log_2[i >> 1] + 1;
  25.     init();
  26.     while (q--) {
  27.         cin >> l >> r;
  28.         cout << mymax(l, r) - mymin(l, r) << endl;
  29.     }

  30.     return 0;
  31. }
复制代码



你不是过了吗?
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-8-20 13:29:05 | 显示全部楼层
sfqxx 发表于 2023-8-20 13:24
你不是过了吗?

是啊,抄课本的
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-20 13:31:48 From FishC Mobile | 显示全部楼层
Ewan-Ahiouy 发表于 2023-8-20 13:29
是啊,抄课本的

给我最佳吧

洛谷基础赛第二题我竟然自己写出来了。

评分

参与人数 1荣誉 +3 收起 理由
Ewan-Ahiouy + 3 鱼C有你更精彩^_^

查看全部评分

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-8-20 13:41:50 | 显示全部楼层
sfqxx 发表于 2023-8-20 13:31
给我最佳吧

洛谷基础赛第二题我竟然自己写出来了。

厉害!
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-20 14:18:09 From FishC Mobile | 显示全部楼层
Ewan-Ahiouy 发表于 2023-8-20 13:41
厉害!

你知道你为什么一直WA吗?

因为输出后需要加end=" "哈哈
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-6-10 08:52

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表