zoukankan      html  css  js  c++  java
  • 【算法】莫队

    莫队是永远也卡不住的。
                             —————— 许多dalao

    很久以前 老师讲了莫队,目的是让我们理解分块思想,当时没时间做笔记(其实是懒的),现在来补上OVO。

    使用范围(纯属个人理解)

    1. 区间求元素种类个数,每种种类元素个数……

    2. 一些看似线段树能做的题但实际上不满足加和性质的题。

    3. 大部分树状数组能做的题。

    (如果有错误请大佬轻点打(doge))

    大概需要的东西

    1. 分块(我不会)

    2. 结构体排序(这个应该是得心应手了)

    3. 疯狂卡常小技巧(不一定需要)

    4. 一个清明的脑子和一双别老手残的手(这个很重要)

    思路过程

    先分块,再排序,最后四个 while 结束一切。

    放个例题(老师的例题)

    洛谷 P1494 [国家集训队]小Z的袜子

    题意概括

    有一个长度为 (n) 的序列,里面的元素为 (c_i) ,有 (m) 组询问,每次询问给出 (l)(r)

    求如果在 ([l,r]) 里任意选两个数字选到相同数字的概率是多少,

    输出答案以分数形式存在。

    数据范围:(n,min[1,50000])(c_i,l,rin[1,n])

    分析

    很明显,这道题符合之前我说的莫队适用情况。

    这时候,就是莫队发威的时候了!!(雾)

    注意:以下过程可能会让人不明不白的,但我会在后面细讲的。

    First

    以每个块为 (sqrt n) 的大小分成 (sqrt n) 个块 。

    Second

    以每个查询区间的左端点所在块顺序排序,

    如果左端点所在块相同,就按照右端点所在块的序数奇偶性排序:

    若右端点在奇数块,顺序排序;

    若右端点在偶数块,倒叙排序。

    Third

    开始遍历所有查询区间,设 (l)(r) 两个指针作为遍历到的区间,

    初始 (l = 1)(r = 0) 代表现在所在区间不存在,

    然后从排好序的查询区间作为询问区间 (ql)(qr)

    如果 (l < ql),就让 (l) 向右移动直到与 (ql) 重合;

    如果 (l > ql),就让 (l) 向左移动直到与 (ql) 重合;

    如果 (r < qr),就让 (r) 向右移动直到与 (qr) 重合;

    如果 (r > qr),就让 (r) 向左移动直到与 (qr) 重合,

    同时让记录 (l)(r) 之间所有种类元素的个数的数组 (cnt) 随遍历到的数字来加减计数。

    Last

    最后求出概率的分母与分子,约分后全部输出。

    解释

    Third

    先说第三步,便于下面的解释。

    一开始,还没有遍历的时候,(l)(r) 是初始化的,大概是这样:

    请不要在意奇怪的数字

    很明显,此时 (l)(r) 之间没有任何元素 。

    我们假定 (ql = 2)(qr = 6)

    而此时 (l) 小于 (ql),所以 (l) 向右移动直到与 (ql) 重合 。

    现在是这样的:

    关于更新 (cnt) 数组

    每次扫到一个数字(无论是 (l) 还是 (r)),

    如果之前扫到过,就说明 (cnt) 数组已经记录下来了这个元素,而现在再扫到说明要将这个元素从 (l)(r) 这个区间中删去,这时候 (cnt--)

    如果之前没有扫到过,就说明 (cnt) 数组没有记录下来,而现在扫到说明要将这个元素从 (l)(r) 这个区间中加上,这时候 (cnt++)

    现在继续模拟:

    既然 (l)(ql) 已经重合了,那么现在需要更新的是 (r) 的位置,于是 (r) 开始向 (qr) 靠拢直到重合:

    于是现在 (cnt) 数组里存的是 (ql)(qr) 的统计值,剩下的只需要在统计的时候按照求概率的公式来就行了,记得用 (ans) 数组记录下当前值,

    毕竟查询下一个区间是在当前区间的基础下完成的。

    First

    分块不必多说,如果不懂就看看 这个

    分块的作用大概就是让上面说的两个指针 (l)(r) 每次不会移动太大的距离:

    (r) 从头到尾一直是从左到右的,而 (l) 则是在一个块里来回移动咣当。

    Second

    莫队的奇偶性排序简直是最玄学的,经老师的一番解释,我大约明白了是怎么回事。

    但我说不出来……

    不过这不重要,最重要的是知道要这么做就好啦(护头,大佬轻点打/doge)

    Last

    个人 jiao 得,这个才是最难得(确信脸),如果不会请看大佬们的题解(这个不属于莫队里的)

    最后

    如果看到这里还不懂的话,就看看这篇吧,

    反正我是看这篇才会的(老师讲课永远 emmmm 懂得)

    膜拜大佬 %%%

  • 相关阅读:
    C#异步编程
    CentOS7下zip解压和unzip压缩文件
    mongodb 按配置文件mongodb.conf启动
    Maven镜像更换为阿里云中央仓库
    Vue项目碰到"‘webpack-dev-server’不是内部或外部命令,也不是可运行的程序或批处理文件"报错
    mysql启动报错cannot allocate memory for the buffer pool处理
    Spring boot Unable to start embedded Tomcat报错 java.lang.NoSuchMethodError: javax.servlet.ServletContext.getVirtualServerName()
    免费桌面视频录像工具OBS的简单操作介绍
    CentOS7下zip解压和unzip压缩文件
    ElasticSearch客户端注解使用介绍
  • 原文地址:https://www.cnblogs.com/EiffelA-blog/p/14130197.html
Copyright © 2011-2022 走看看