当前位置: 首页 > wzjs >正文

影视传媒公司网站模板旅行网站开发意义

影视传媒公司网站模板,旅行网站开发意义,小型网站设计,新农宝网站建设方案莫队算法 —— 将暴力玩出花 一、 为什么需要莫队?—— 暴力法的瓶颈 我们已经学会了用分块处理一些在线的区间问题。现在,我们来看一类特殊的离线区间查询问题。 “离线”意味着我们可以把所有查询先读进来,再按我们喜欢的顺序去处理它们…

莫队算法 —— 将暴力玩出花

一、 为什么需要莫队?—— 暴力法的瓶颈

我们已经学会了用分块处理一些在线的区间问题。现在,我们来看一类特殊的离线区间查询问题。

“离线”意味着我们可以把所有查询先读进来,再按我们喜欢的顺序去处理它们。

思考一个问题:

给定一个长度为 N 的数组,M 次询问。每次询问一个区间 [l, r],问区间内有多少种数字至少出现了2次?

那我们回到最朴素的暴力。

  • 纯暴力:对于每个询问 (l, r),都for一遍,用数组统计词频。复杂度 O(M * N),无法接受。

  • 聪明的暴力:我们发现,如果已经知道了区间 [l, r] 的答案,我们似乎可以很快地算出相邻区间的答案。

    • [l, r+1] 的答案:在 [l, r] 的基础上,加入 a[r+1] 这个元素。
    • [l-1, r] 的答案:在 [l, r] 的基础上,加入 a[l-1] 这个元素。
    • [l+1, r] 的答案:在 [l, r] 的基础上,删去 a[l] 这个元素。
    • [l, r-1] 的答案:在 [l, r] 的基础上,删去 a[r] 这个元素。

这种“加入/删除一个元素”的操作,通常可以在 O(1)O(log N) 的时间内完成。这给了我们一个启发:我们可以维护一个当前区间 [L, R],通过不断移动左右端点 LR,来回答所有的查询。

新的瓶颈:如果我们按照读入的顺序处理询问,[L, R] 指针可能会在整个数组上“疯狂横跳”。比如前一个询问是 [1, 10],后一个询问是 [99990, 100000],指针移动的距离是 O(N)M 次询问,总复杂度最坏还是 O(M * N)

莫队算法的核心,就是解决这个问题:通过对询问进行巧妙的排序,最小化指针移动的总距离。

二、 莫队的核心思想 —— 分块排序

莫队算法的精髓在于它独特的排序策略,它将分块思想运用到了对“询问”的排序上。

  1. 分块:将长度为 N原数组下标分成 √N 个块,每块长度为 s = √N
  2. 排序:对所有询问 (l, r) 进行排序,规则如下:
    • 第一关键字:以询问的左端点 l 所在的块的编号为第一关键字,升序排列。
    • 第二关键字:如果 l 在同一个块内,则以询问的右端点 r 为第二关键字,升序排列。
// 排序规则
bool operator < (const Query& a, const Query& b) {if (belong[a.l] != belong[b.l]) {return belong[a.l] < belong[b.l]; // l 不在同块,按块编号排}return a.r < b.r; // l 在同块,按 r 排
}

为什么这样排序是高效的?
我们来直观地感受一下指针的移动:

  • 左指针 L

    • 当处理同一块内的所有询问时,l 的变化范围不会超过块长 √N。因此 L 每次也会在一个 √N 的范围内移动。
    • 当处理完一个块,换到下一个块时,L 才可能发生一次大的跳跃。
  • 右指针 R

    • 当处理同一块内的所有询问时,由于这些询问的 r 是升序的,所以 R 指针会单调向右移动,从左到右扫一遍。
    • 当处理完一个块,换到下一个块时,R 的位置是无序的,可能会从数组末尾跳回开头。

现在,我们来严格分析一下它的时间复杂度。

三、 复杂度分析

假设我们有 M 个询问,数组长度 N,块长 s = √N,块数n = √N。每次指针移动后更新答案的代价是 O(1)

1. 右指针 R 的移动

  • 块内移动:对于左端点在同一个块 i 的所有询问,它们的右端点 r 是递增的。所以,R 指针在处理这整个块的询问时,最多从 1 移动到 N,总移动距离是 O(N)。因为有 √N 个块,所以这部分总移动距离是 O(N * √N)
  • 块间移动:当左端点从一个块 i 换到下一个块 i+1 时,R 指针可能会从 N 跳回 1。这个过程最多发生 √N - 1 次。每次跳跃的成本是 O(N)。所以这部分总移动距离是 O(N * √N)

综合来看,右指针 R 的总移动次数是 O(N√N)

2. 左指针 L 的移动

  • 块内移动:对于任意一个询问,L 从上一个询问的左端点 l_{prev} 移动到当前询问的左端点 l_{cur}。由于 l_{prev}l_{cur} 在同一个块,它们之间的距离最多是块长 s,即 √N。所以每次移动距离是 O(√N)
  • 块间移动:当左端点从一个块 i 移动到下一个块 i+1 的时,移动距离最多是 2s,即 O(√N)

L 的每一次移动,无论是块内还是块间,距离都不会超过 O(√N)。总共有 M 个询问,所以左指针 L 的总移动次数是 O(M√N)


让我们用一个正确且有效的例子来演示这个过程

假设我们的查询是这些:(2, 5), (4, 9), (1, 18), (7, 8), (8, 12), (5, 20)

标准排序(无优化)
  1. 分块:左端点 l 属于块1(1-4)的有 (2, 5), (4, 9), (1, 18)。左端点 l 属于块2(5-8)的有 (7, 8), (8, 12), (5, 20)

  2. 排序

    • 块1内:按 r 升序 -> (2, 5), (4, 9), (1, 18)
    • 块2内:按 r 升序 -> (7, 8), (8, 12), (5, 20)
  3. 处理顺序与 R 指针移动

处理顺序查询 (l, r)R 的移动R 当前位置
1(2, 5)0 -> 55
2(4, 9)5 -> 99
3(1, 18)9 -> 1818
—换块—
4(7, 8)18 -> 88
5(8, 12)8 -> 1212
6(5, 20)12 -> 2020

总时间复杂度
将两部分加起来,总复杂度为 O(N√N + M√N)。如果 NM 同阶,就是 O(N√N)

**3. 奇偶性排序优化 **
我们发现,R 指针在换块时的大幅回跳是性能瓶颈之一。可以这样优化:/

  • 如果左端点 l 所在的块编号是奇数,则按 r 升序排。
  • 如果左端点 l 所在的块编号是偶数,则按 r 降序排。
// 奇偶性排序
bool operator < (const Query& a, const Query& b) {if (belong[a.l] != belong[b.l]) {return belong[a.l] < belong[b.l];}// 如果 belong[a.l] 是偶数,则 r 降序if (belong[a.l] % 2 == 0) {return a.r > b.r;}// 如果 belong[a.l] 是奇数,则 r 升序return a.r < b.r;
}

这样,R 指针在处理完一个块后,换到下一个块时,就无需从 N 回跳到 1,而是从当前位置继续“回头”扫描,如同耕地一样。这能省掉 R 指针换块时的 O(N) 的开销,总复杂度依然是 O(N√N + M√N),但常数会小很多。

假设我们的查询是这些:(2, 5), (4, 9), (1, 18), (7, 8), (8, 12), (5, 20)


场景二:奇偶性排序优化
  1. 排序

    • 块1(奇数块):按 r 升序 -> (2, 5), (4, 9), (1, 18)
    • 块2(偶数块):按 r 降序 -> (5, 20), (8, 12), (7, 8)
  2. 处理顺序与 R 指针移动

处理顺序查询 (l, r)R 的移动R 当前位置
1(2, 5)0 -> 55
2(4, 9)5 -> 99
3(1, 18)9 -> 1818
—换块—
4(5, 20)18 -> 2020
5(8, 12)20 -> 1212
6(7, 8)12 -> 88

在这个优化版本中,当从块1换到块2时,R 指针从 18 平滑地移动到了 20完全避免了大幅回跳。然后,在处理整个块2的过程中,R 指针再从右向左“扫描”回来。

四、 经典例题:小Z的袜子

我们来看知乎文章里的经典例题 P1494 [国家集训队]小Z的袜子。

题意:区间 [l, r] 内,随机取两只袜子,颜色相同的概率是多少?化为最简分数。

分析

  • 设区间长度为 len = r - l + 1
  • len 只袜子中取两只,总方案数是 C(len, 2) = len * (len-1) / 2
  • 设颜色 i 出现了 cnt[i] 次。取出两只颜色为 i 的方案数是 C(cnt[i], 2) = cnt[i] * (cnt[i]-1) / 2
  • 所有颜色都算上,取出两只相同颜色的总方案数是 Σ C(cnt[i], 2)
  • 概率 P = (Σ C(cnt[i], 2)) / C(len, 2) = (Σ (cnt[i]² - cnt[i])) / (len * (len-1))

核心任务
推导最优块长

我们来一步步推导。

1. 重新审视时间复杂度的构成

莫队算法的总时间开销主要来自两部分:

  1. 左指针 L 的移动开销
  2. 右指针 R 的移动开销

(排序的开销 O(M log M) 通常被指针移动的开销覆盖,我们在此暂不考虑。)

我们的目标是:选择一个合适的块长 s,使得这两部分开销之和最小。

2. 用块长 s 来表示开销

设数组长度为 N,询问数量为 M,块长为 s
那么,数组被分成的块数就是 ceil(N/s),我们近似看作 N/s

  • 左指针 L 的总移动距离:

    • 块内移动:当处理同一块内的询问时,左端点 l 的变化范围不会超过块长 s
    • 块间移动:当从一个块换到下一个块时,左指针 L 最多移动 2s 的距离。
    • 对于 M 次询问,每次询问 L 最多移动 O(s) 的距离。所以,L 的总移动次数是 O(M * s)
  • 右指针 R 的总移动距离:

    • 块内移动:对于左端点在同一个块的所有询问,由于我们对右端点 r 进行了排序(无论是单调递增还是奇偶性优化),R 指针在处理这一个块的所有询问时,最多会把 1N 的范围完整地扫一遍(或者来回扫一遍)。所以处理一个块的 R 指针移动开销是 O(N)
    • 总移动:我们总共有 N/s 个块。因此,R 指针的总移动次数就是 (块数) * (处理每块的开销),即 O((N/s) * N) = O(N^2 / s)

3. 使用均值不等式求解最优 s

现在,我们得到了总的指针移动次数(时间复杂度的主要部分):
T ( s ) = M ⋅ s + N 2 s T(s) = M \cdot s + \frac{N^2}{s} T(s)=Ms+sN2
我们的任务是找到一个 s,使得 T(s) 最小。

4. 计算最低时间复杂度

我们将最优块长 s = N / √M 代入到总复杂度 T(s) 中:
T m i n = M ⋅ ( N M ) + N 2 ( N M ) T_{min} = M \cdot \left(\frac{N}{\sqrt{M}}\right) + \frac{N^2}{\left(\frac{N}{\sqrt{M}}\right)} Tmin=M(M N)+(M N)N2

T m i n = N ⋅ M + N 2 ⋅ M N T_{min} = N \cdot \sqrt{M} + N^2 \cdot \frac{\sqrt{M}}{N} Tmin=NM +N2NM

T m i n = N M + N M = 2 N M T_{min} = N\sqrt{M} + N\sqrt{M} = 2N\sqrt{M} Tmin=NM +NM =2NM

所以,总时间复杂度为 O(N√M)

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define close ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
int n, m;
int B;
int tot;
const int N = 5e4 + 10;
int belong[N];
int a[N];
int ans = 0;
int cnt[N];
struct ss
{int l;int r;int index;int fz;int fm;
};
void build()
{for (int i = 1; i <= n; i++){belong[i] = (i - 1) / B + 1;}
}
void add(int x)
{if (cnt[a[x]] >= 2){ans -= (cnt[a[x]]) * (cnt[a[x]] - 1);}++cnt[a[x]];if (cnt[a[x]] >= 2){ans += (cnt[a[x]]) * (cnt[a[x]] - 1);}
}
void del(int x)
{if (cnt[a[x]] >= 2){ans -= (cnt[a[x]]) * (cnt[a[x]] - 1);}--cnt[a[x]];if (cnt[a[x]] >= 2){ans += (cnt[a[x]]) * (cnt[a[x]] - 1);}
}
void solve()
{cin >> n >> m;B = n / sqrt(m);tot = (n + B - 1) / B;for (int i = 1; i <= n; i++){cin >> a[i];}build();vector<ss> q;for (int i = 1; i <= m; i++){int l, r;cin >> l >> r;q.push_back({l, r, i, 0, 0});}sort(q.begin(), q.end(), [&](const ss &x, const ss &y){if(belong[x.l] != belong[y.l]){return belong[x.l] < belong[y.l];}if(belong[x.l] % 2 == 0){return x.r < y.r;}else{return x.r > y.r;} });int L = 1, R = 0;for (int i = 0; i < m; i++){int cntLen = q[i].r - q[i].l + 1;q[i].fm = cntLen * (cntLen - 1);while (L > q[i].l){add(--L);}while (L < q[i].l){del(L++);}while (R < q[i].r){add(++R);}while (R > q[i].r){del(R--);}if (ans == 0 or q[i].l == q[i].r){q[i].fz = 0;q[i].fm = 1;}else{int com = __gcd(ans, q[i].fm);q[i].fz = ans / com;q[i].fm = q[i].fm / com;}}sort(q.begin(), q.end(), [&](const ss &x, const ss &y){ return x.index < y.index; });for (int i = 0; i < m; i++){cout << q[i].fz << "/" << q[i].fm << endl;}
}
signed main()
{close;solve();return 0;
}

文章转载自:

http://CrIvN8ux.xdmsq.cn
http://kEDPwxg5.xdmsq.cn
http://V5sB3G2O.xdmsq.cn
http://1LIr0wKP.xdmsq.cn
http://eVu8cWvd.xdmsq.cn
http://f3Dz6U2j.xdmsq.cn
http://v25LIlHe.xdmsq.cn
http://yFllv6rJ.xdmsq.cn
http://FSeXMMu4.xdmsq.cn
http://dv2BJISy.xdmsq.cn
http://SC5Iam1m.xdmsq.cn
http://CXguMUS6.xdmsq.cn
http://kC9x5Aa1.xdmsq.cn
http://cH49kNK8.xdmsq.cn
http://IMmfZgpB.xdmsq.cn
http://ab8V2hCX.xdmsq.cn
http://HKTGcuV6.xdmsq.cn
http://VNT8cwnl.xdmsq.cn
http://OYxcggbq.xdmsq.cn
http://qJkoXd9V.xdmsq.cn
http://uvq7a2Xz.xdmsq.cn
http://O9rTIe3v.xdmsq.cn
http://jKOubDNx.xdmsq.cn
http://n58HOJjQ.xdmsq.cn
http://Er0sZVkL.xdmsq.cn
http://AELoPb4Z.xdmsq.cn
http://fUq3ttcR.xdmsq.cn
http://vt71YlSm.xdmsq.cn
http://BV1RdPFQ.xdmsq.cn
http://UKuuRAx4.xdmsq.cn
http://www.dtcms.com/wzjs/686152.html

相关文章:

  • 做任务挣钱的网站聚河南高端网站
  • 有名的产品设计公司seo推广软件代理
  • 做博客和做网站大学生为什么不去中建
  • net网站开发环境电脑培训机构哪里有
  • 动漫网站开发 百度一下wordpress 产品主题
  • 广安市国土资源局网站建设线上设计师接单
  • 企业网站建设的方法有哪些计算机论文8000到10000字
  • 天水市秦州区作风建设年网站用凡科帮别人做网站
  • 国内知名的网站建设企业怎么自己注册网站
  • 优秀个人网站欣赏会员卡管理系统多少钱一套
  • 商场网站设计建设教育培训的网站
  • 公司建网站一般多少钱推广策划公司
  • 怎么查询网站是否收录网页无法访问手机
  • 沧州大型网站建设百度指数功能模块
  • 江苏做网站xlech5模板下载有哪些网站
  • 莱芜泉网站建设做鲜花的网站有哪些
  • 九尾狐建站网址免费网站建设找哪家
  • 仿牌外贸网站制作ps如何做切片网站按钮
  • 网站开发怎么让别人看到简易个人网页模板
  • 济南网站推广优化在线做家装设计的网站
  • 苏州seo建站网站建设 申请报告
  • 青岛网站推广哪家效果好优化方案2021版英语
  • 网站建设合同属于什么合同公司官网登录入口
  • 网站平台系统设计公司房产管理系统
  • 简述建设网站的具体步骤无锡新吴区住房建设和交通局网站
  • 织梦 帝国 php cms 媒体网站 哪个无锡响应式网站设计
  • 网站建设费用是多少钱网站文章编辑
  • 深圳西乡 网站建设自己做的网站怎么才能被收录
  • 股票网站模板天空台108网站找手工活带回家做
  • 网站建设淄博佳铉网络做教育导航的网站