莫队算法讲解 (详尽版)

来源:互联网 发布:程序员面试简历模板 编辑:程序博客网 时间:2024/05/18 02:28

莫队算法我早有耳闻。。可惜前不久才去学习。

但是自己看了看论文,也就1h左右,就能够全部理解了。

也就是说其实这个算法不难。。

好了,让我们进入正题。


我们首先来看一道例题:

Description

    有n个数字,给出k,以及m个查询。

    每次查询的格式是L,r,求L~r(左右包含)这个区间内数字的出现次数刚好是k的数字种数。

    范围:n<=30000,k<=n,m<=30000,1<=L<r<=n,数列中元素大小<=n。

    输入n,k,m,然后n个元素,然后m行查询,对于每一个询问,输出正确的答案。

Example input:

5 2 3

1 2 3 2 2

1 2

2 4

1 5

Example output:

0     //没有

1     //2

0     //没有(2太多了,也不算)

我们来考虑一下这题的解法。

首先肯定可以万能暴力,每次L~r枚举。时间复杂度O(N*M)。

但是这样的暴力是没有前途的!我们来考虑一下新的暴力:

一开始指针区间0->0,然后对于一个查询,我们将Left指针逐步更新成新的L,Right同理。

比如一开始Left=2,Right=3,而L=1,r=5。

那么我们Left-1,并且把Left位置上的数字出现次数+1.

Right+1,把Right位置上的数字出现次数+1,直到Right=5为止。

框架:

add(x){  //把x位置的数字加入进来    cnt[x]++;    if (cnt[x]==k) ans++;}remove(x){  //把x位置的数字移出去    cnt[x]--;    if (cnt[x]==k-1) ans--;}

然后以上面题目为例;这种方法需要离线处理,我们同理来看一下解法:

Left=Right=1; add(1);ans=0;for u=1 to m{    while (Left<L[u]){  remove(Left); Left++;}    while (Left>L[u]){  Left--; add(Left);}    while (Right<r[u]){  Right++; add(Right};}    while (Right>r[u]){  remove(Right); Right--;}    output ans;}

这里说明一下,其实remove(Left);Left--;等等可以直接写成remove(Left--)等等,我这么写是为了理解。

分析一下时间复杂度,我们可以从Left和Right的移动量来分析:

每一个新的询问,Left和Right的移动量最大都会是O(N)

所以这样子的方法时间复杂度仍然是O(N*M),而且可能比上面的暴力更慢。

但是莫队算法的核心,就是从这么一个算法转变过来的。

现在来介绍一下莫队算法解决这道题:

对询问进行分块,我们知道m个询问,L和r的范围都在n以内,我们根据L和r的大小来对询问分块。

比如n=9,有以下的询问:

2 3

1 4

4 5

1 6

7 9

8 9

5 8

6 8

对于n=9,我们以根号n为每个块block的大小,这里block=3.

那么我们把1~3分成一组,4~6,7~9.

对于每一个询问(L,r),我们以L的范围来决定这个询问在哪一个块。

然后每一个独自的块内,我们让询问r更小的排在更前面。

那么上面的询问就可以分组成:

(2,3)/(1,4)/(1,6)和

(4,5)/(5,8)/(6,8)和

(7,9)/(8,9)

这一步的排序操作,我们可以在排序的时候加入判断条件cmp:

bool cmp(Query x,Query y){    if ((x/block)!=(y/block))        return x.L<y.L;        //不同块的时候    return x.r<y.r;      //同一块的时候}


排序之后,我们再来分析一下时间复杂度;接下来我们会看到神奇的事情!!

刚才分析此方法的时候,我们是从L和R的偏移量分析的;我们仍然用这种方法来分析。

考虑一下在同一个块的时候。由于L的范围是确定的,所以每次L的偏移量是O(√N)

但是r的范围没有确定;r的偏移量是O(N)。

那么从一个块到另一个块呢?

明显地,r我们不需要作考虑,仍然是O(N)。

而L明显最多也是2*√N,而且这种情况下,很快就会到下下一块。所以也是O(√N)

由于有√N(根号N)个块,所以r的总偏移量是O(N*√N)

而M个询问,每个询问都可以让L偏移O(√N),所以L的总偏移量O(M*√N)

注意了,时间复杂度分析的时候一定要注意,r的偏移量和询问数目是没有直接关系的。

而L则恰恰相反;L的偏移量我们刚才也说明了,它和块的个数没有直接关系。

所以总的时间复杂度是:

O((N+M)*√N)

很神奇地看到了,我们仅仅改变了一下问题求解的次序,就让时间复杂度大幅度下降!

当然这个说明过程我们也看到了,事实上,莫队是一个必须离线的算法。

意味着一些题目如果强制在线,那么莫队就无能为力了。


代码就不总结了,可以看上面的分块的地方,也可以看一些莫队的题目的题解。


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 电脑卡怎么办怎么清理磁盘 苹果手机设置找不到了怎么办 苹果手机自动拨出电话怎么办 机械键盘灯坏了怎么办 黄金塔花叶子卷怎么办 办的宽带不用了怎么办 取卵后3天还出血怎么办 取卵后腹水怎么办9天了 取卵后第三天肚子涨第天移植怎么办 取卵移植后肚子涨怎么办 没有成熟的卵泡不排卵怎么办 产后9年妊娠纹痒怎么办 手机屏幕锁了忘记密码怎么办 电脑被黑客锁屏怎么办 r9解锁密码忘了怎么办 oppor9开机密码忘了怎么办 vivo手机忘记解锁图案怎么办 oppor9s解锁图案忘了怎么办 oppor9图案解锁忘记了怎么办 oppor9解锁图案忘了怎么办 oppor9s锁屏密码忘了怎么办 oppor9s忘记锁屏图案怎么办 oppor9忘记锁屏图案怎么办 电脑锁屏卡住了怎么办 dell电脑密码忘了怎么办 dell电脑密码忘记了怎么办 手机锁屏为什么打不开怎么办 手机图形解锁忘记了怎么办 华硕电脑锁屏了怎么办 5s忘记解锁密码怎么办 苹果手机密码忘记了怎么办 苹果手机iphone已停用怎么办 手机被停用怎么办不用电脑 激活锁是别人的怎么办 6s开机密码忘了怎么办 苹果手机忘记解锁密码怎么办 忘记苹果触控id怎么办 苹果6app被锁了怎么办 捡的苹果id锁了怎么办 苹果手机id密码锁了怎么办 美版5s刷机后激活怎么办