跟风学莫队,发现竟不会。博客一大堆,不知该看谁。

刚开始要学习莫队的时候发现那么多的博客,真有乱花渐欲迷人眼的感觉,后来觉得不妨看看集训队的论文,才发现根本找不到,说是10-13年是作业的形式,根本没发表论文,那就只好一篇篇的去浏览,找到适合自己的。研究良久,觉得是时候对莫队做一波总结了。

首先明白莫队可以解决的问题:区间问题
类似这种:有n个数的整数数列,给出区间[l,r],求[l,r]中的计数问题,特点就是数组是静态的,但是动态查询。其他数据结构可以维护,但是有的时间复杂度太大,有的代码冗杂,莫队应运而生。

莫队的实现:可以在O(1)的时间内把[l,r]的询问转移到[l-1,r],[l+1,r],[l,r-1],[l,r+1]的询问,而且不需要修改操作,此时可以使用莫队算法来解决此问题。

首先以求[l,r]之间的出现次数为k次的数的个数为例,正常暴力的想法是每次跑一次[l,r],然后不超时算我输。这里做一个假设,假设区间[l,r]的答案已经得到,求[l`,r`]的答案,利用指针偏移的思想,让l去找l`,让r去找r`,这样得到时间复杂度是的算法,然后这可以看作点P(l,r)到点P`(l`,r`)的曼哈顿距离,然后对于所有m次询问,求一个最小生成树就是最理想的答案。这种算法叫最优曼哈顿距离生成树,为什么要介绍这个,因为要体现莫队的优越性啊,首先这样时间耗时是O(n^2*logn),m询问次数接近于n,故用n表示,然后代码长度可想而知,在已经区间[l.r]的基础上,引出莫队。

莫队的核心:分块,为什么要分块?假设已知区间[l.r]的解,正常情况的话最优的优化是曼哈顿生成树,但是,如果将序列分块的话,会发现意想不到的惊喜。已知[l,r],易得[l-1,r],[l,r+1],[l,r-1],[l-1,r-1],将所有的块进行排序,按左端点排序,若是左端点相同,就按右端点排序。然后去求解,类似于上面的算法,用两个指针去解决,要是所求区间在当前分块内,只需要移动右指针,此时的时间复杂度最大是O(n),因为是按照左端点和右端点两个关键字排序,所以右指针显然是递增的,即O(n),然后若是不在当前区间内,就移动左指针,左指针也是有序的最多进行分的块数次,通常分块会取次,得到总的时间复杂度,也就是通常所说的n的1.5次幂,莫队算法结束。

不难发现此算法的优点就是代码量少,而且时间复杂度可以接受,用通俗的语言再讲一下莫队的实现:将整个区间分块,分块后将所有的查询进行排序,将查询的区间不断移动,无非是左右指针的移动,最后得到每一次查询的答案,按照查询的顺序,输出答案。This is 神奇的莫队,This is 号称解决一切区间问题的莫队

拿个例题说明一下: BZOJ 2038 小Z的袜子(hose)
这是引出莫队算法的题目,也是最基础最能说明莫队的题目。分析此题的答案由两部分组成,分母部分是区间的长度的平方(不考虑组合,只考虑排列),分子是所有满足条件的平方和,考虑枚举区间,维护一个ans值,用一个数组去记录当前每种颜色出现的次数,首先是左指针右移,出现的结果就是某种颜色的值-1,不妨先把所有这种颜色的贡献都减去,然后更新这种颜色的贡献,最后都加上,得到ans值,最后ans值减去区间的长度就是分子,分母就是区间长度的平方。由于此题网上题解众多,此处就不多赘述,建议自己写一下,体会一下莫队的神奇。

代码实现:

/*
Look at the star
Look at the shine for U
*/ #include<bits/stdc++.h>
#define sl(x) scanf("%d",&x)
#define PII pair<ll,ll>
using namespace std;
typedef long long ll;
const int N = 1e6+5;
const ll mod = 1e9+7;
const ll INF = 0x3f3f3f3f;
struct node{int l,r,index;ll x,y;
}p[N];
ll sum[N],ans;
int s[N],cnt,num[N];
bool cmp(node a,node b) {return num[a.l] == num[b.l] ? a.r < b.r : a.l < b.l;}
bool CMP(node a,node b) {return a.index < b.index;}
void update(int x,int add)
{ans -= sum[s[x]]*(sum[s[x]]);sum[s[x]] += add;ans += sum[s[x]]*(sum[s[x]]);
}
int main()
{int n,m,i,j,k;sl(n);sl(m);cnt = pow(n,0.57);for(i = 1;i <= n;i++) sl(s[i]),num[i] = i/cnt+1;for(i = 1;i <= m;i++) sl(p[i].l),sl(p[i].r),p[i].index = i;sort(p+1,p+1+m,cmp);int l = 1,r = 0;for(i = 1;i <= m;i++){while(l < p[i].l) update(l,-1),l++;while(l > p[i].l) update(l-1,1),l--;while(r < p[i].r) update(r+1,1),r++;while(r > p[i].r) update(r,-1),r--;if(p[i].l == p[i].r){p[i].x = 0;p[i].y = 1;continue;}p[i].x = ans-(p[i].r-p[i].l+1);p[i].y = 1ll*(p[i].r-p[i].l+1)*(p[i].r-p[i].l);ll gcd = __gcd(p[i].x,p[i].y);p[i].x /= gcd;p[i].y /= gcd; }sort(p+1,p+1+m,CMP);for(i = 1;i <= m;i++) printf("%lld/%lld\n",p[i].x,p[i].y);
}

异或序列 思维莫队
题意是给定一堆数,给出m次询问,问[l,r]之间,有多少个子区间的抑或和等于k。

此题要考虑如何在区间移动的过程中保证答案的正确性,根据异或的性质:a^b = c 即有a^c = b, b^c = a。推广到pre的异或,和,pre[i-1]^pre[i] = k, 即有 pre[i-1]^k = pre[i], pre[i-]^k = pre[i-1]。这样就可以在区间移动的过程中维护答案了。

代码实现:

/*
Look at the star
Look at the shine for U
*/ #include<bits/stdc++.h>
#define sl(x) scanf("%d",&x)
#define PII pair<ll,ll>
using namespace std;
typedef long long ll;
const int N = 1e6+5;
const ll mod = 1e9+7;
const ll INF = 0x3f3f3f3f;
struct node{int l,r,index;ll ans;
}p[N];
ll sum[N],ans;
int s[N],cnt,num[N],n,m,k;
bool cmp(node a,node b) {return num[a.l] == num[b.l] ? a.r < b.r : a.l < b.l;}
bool CMP(node a,node b) {return a.index < b.index;}void update(int x,int add)
{if(!add){sum[s[x]]--;ans -= sum[s[x]^k];}else{ans += sum[s[x]^k];sum[s[x]]++;}
}int main()
{int i,j;sl(n),sl(m);sl(k);cnt = pow(n,0.57);for(i = 1;i <= n;i++) sl(s[i]),num[i] = i/cnt+1,s[i] ^= s[i-1];for(i = 1;i <= m;i++) sl(p[i].l),sl(p[i].r),p[i].index = i;sort(p+1,p+1+m,cmp);int l = 1,r = 0;sum[0] = 1;for(i = 1;i <=m;i++){while(l < p[i].l) update(l-1,0),l++;while(l > p[i].l) l--,update(l-1,1);while(r < p[i].r) update(++r,1);while(r > p[i].r) update(r--,0);p[i].ans = ans;}sort(p+1,p+1+m,CMP);for(i = 1;i <= m;i++) printf("%lld\n",p[i].ans);
}

通过以上两个题可以发现,莫队的关键是找到区间移动事维护答案的状态,即找到计数数组,并在区间移动的时候维护答案,技巧性比较大,所以还是多做题,熟能生巧。

Hello 莫队----莫队算法小结相关推荐

  1. 数据挖掘中分类算法小结

    数据挖掘中分类算法小结   数据仓库,数据库或者其它信息库中隐藏着许多可以为商业.科研等活动的决策提供所需要的知识.分类与预测是两种数据分析形式,它们可以用来抽取能够描述重要数据集合或预测未来数据趋势 ...

  2. [转载]SIFT(尺度不变特征变换)算法小结

    原文地址:SIFT(尺度不变特征变换)算法小结[转]作者:慕容天峰 最近一直在看SIFT算法.Sift是David Lowe于1999年提出的局部特征描述子,并于2004年进行了更深入的发展和完善.S ...

  3. linemod算法小结

    Linemod算法小结   LineMod方法是由Hinterstoisser[1][2][3]在2011年提出,主要解决的问题是复杂背景下3D物体的实时检测与定位,用到了RGBD的信息,可以应对无纹 ...

  4. 分治算法小结(附例题详解)

    分治算法小结(附例题详解) 我的理解: 分治算法我的理解就是看人下菜碟,我们要解决的问题就好像一群人构成的集体,要我们解决这个问题,那我们就要满足这群人里面每个人不同的需求,也就是写出解决的代码,把每 ...

  5. 红队蓝队紫队具体是指什么

    红队 什么是红队 红队,是指网络实战攻防演练中的防守一方. 红队一般是以参演单位现有的网络安全防护体系为基础,在实战 攻防演练期间组建的防守队伍.红队的主要工作包括演练前安全检 查.整改与加固,演练期 ...

  6. Fast Gradient Sign Attack(FGSM)算法小结

    Fast Gradient Sign Attack(FGSM)算法小结 对抗攻击引发了机器学习一系列的思考,训练出来的model是否拥有强大的泛化能力?模型的准确率是否真实? 在对抗攻击中添加一些肉眼 ...

  7. 莫西莫西是错的?你不知道的日语电话姿势

    莫西莫西是错的?你不知道的日语电话姿势 童鞋们最熟悉的日语电话打开方式是什么?对!就是拨通以后,喊「もしもし」,也就相当于"喂".但是这个词在商务场合是禁语.╮( ̄▽ ̄)╭你知道为 ...

  8. 用标志域tag判断队空队满的入队和出队算法

    题目: 若希望循环队列中的元素都能得到利用,则需设置一个标志域tag,并以tag的值为0或1来区分队头指针front和队尾指针rear相同时队列状态是空还是满.试编写与此结构相对应的入队和出队算法. ...

  9. c语言循环队列入列算法,C语言——循环队列和链队列的基本运算

    // 循环队列 #include #include "SeqQue.h" // 循环队列的基本运算 /* const int maxsize = 20; typedef struc ...

最新文章

  1. linux进行主机发现,linux – 网络上所有计算机的主机名发现
  2. .NET Core容器化之多容器应用部署@Docker-Compose
  3. python类继承返回值_python继承threading.Thread实现有返回值的子类实例
  4. 不同版本的mysql_windows下如何让多个个不同版本的mysql共存-百度经验
  5. 【华为云技术分享】敏捷DevOps知识卡大全(内附下载资料)
  6. python自动卸载win程序_利用python实现自动扫雷程序
  7. 6 万出头的北京房价,程序员如何靠自己安家?
  8. jms pub/sub模型_JMS消息传递模型:点对点和发布/订阅
  9. BootStrap_04之jQuery插件(导航、轮播)、以及Less
  10. pyhon如何连接mysql_python如何连mysql数据库
  11. 容器技术Docker K8s 29 容器服务ACK基础与进阶-弹性伸缩
  12. 彻底卸载SQL Server
  13. CSDN-markdown编辑器语法——背景色
  14. WordPress社交网络菜单图标更改——SVG图标
  15. CrossApp 设置App启动页(无任何黑屏白屏,显示完启动画面之间到显示出首页界面)
  16. vsphere esxi原生下载方式
  17. 用了三星Dex,我已经快一个月回家没开过电脑了
  18. 直接学 Vue 3 吧 —— 对话 Vue.js 作者尤雨溪
  19. 系统文件IO与标准文件IO
  20. 连续子串最大和——python实现

热门文章

  1. 计算机管理任务计划程序损坏,处理设置任务计划程序win10中出错不可用的方法...
  2. JSON 对象的这些操作和使用场景你知道多少?
  3. 《图解密码技术》第三章 对称密码(共享密玥密码)
  4. 在家工作多年再回深圳找工作,会不会丢脸?
  5. reduce的梦幻用法
  6. 包职院计算机专业代号,高职专业代码查询2017
  7. 【leetcode】把数字翻译成字符串 c++
  8. 在办公室吃东西的同事,长点心吧!
  9. 如何设置RTOS任务的堆栈大小?
  10. 123网校 计算机一级,全国计算机一级MS Office试题(三)