首页 > 其他分享 >莫队学习笔记

莫队学习笔记

时间:2023-07-01 21:33:16浏览次数:41  
标签:cnt 复杂度 sqrt 学习 leq 笔记 莫队 LL

引入问题

给出一个长度为 \(n\) 的数组 \(A\),接下来 \(q\) 次询问,每次询问求 \([l,r]\) 中有多少组 \((i,j,k)\) 使得 \(a_i=a_j=a_k(i<j<k)\)。

保证 \(1\leq n\leq 10^5,1\leq A_i\leq n(1\leq i\leq n)\)。

莫队的基础思想——区间转移

简单分析问题,貌似并没有可加性,所以分块和线段树肯定寄了。

但是本题中相邻区间转移是 \(O(1)\):

  • 对于增加元素,设原有此元素 \(n\) 个,则增加三元组 \(\dfrac 1 2n(n-1)\) 个。
  • 对于删除元素,设减去该元素后有此元素 \(n\) 个,则减少三元组 \(\dfrac 1 2n(n-1)\) 个。

莫队算法是一种解决此类问题的离线算法,它基于以下思想:

我们不难考虑到一个暴力代码,它的框架如下:

void del(LL x)
{
	cnt[a[x]]--;
	sum-=cnt[a[x]]*(cnt[a[x]]-1)/2;
}
void ins(LL x)
{
	sum+=cnt[a[x]]*(cnt[a[x]]-1)/2;
	cnt[a[x]]++;
}
LL l=1,r=0,sl,sr;
for(int i=1;i<=q;i++)
{
	sl=b[i].l,sr=b[i].r;
	while(l<sl)del(l++);
	while(sl<l)ins(--l);
	while(r<sr)ins(++r);
	while(sr<r)del(r--);
	ans[b[i].id]=sum;
}

该代码中出现的函数,ins(x) 表示算上 \(x\) 这一项的贡献,del(x) 表示删除 \(x\) 这一项的贡献。

不难看出,这份代码本质上是对于询问区间的移动。

如果我们保证区间移动次数较少的话,时间复杂度也会比较优秀。

我们有什么思路呢?

时间复杂度优秀的秘密——分块

我们取 \(B=\sqrt n\) 为块长进行分块,然后,按照左边界所在的块的编号给询问区间排序,同一个块则用右边界排序。

不难得到如下代码:

bool cmp(node x,node y)
{
	if(x.l/B==y.l/B)return x.r<y.r;
	return x.l/B<y.l/B;
}

我们来分析一下时间复杂度:

  • 左边界块内移动,每次时间复杂度 \(O(\sqrt n)\),有 \(q\) 次,时间复杂度为 \(O(q\sqrt n)\)。
  • 左边界越块移动,每次翻过一个块的时间复杂度是 \(O(\sqrt n)\),有 \(\sqrt n\) 次,时间复杂度为 \(O(n)\)。
  • 对于每个左边界的块,右边界的移动整体来看都是 \(O(n)\) 的,有 \(\sqrt n\) 个块,时间复杂度为 \(O(n\sqrt n)\)。

因此,莫队的整体时间复杂度是 \(O(n\sqrt n)\)。

玄学优化——奇偶性优化

对于编号为奇数的块,我们用右边界从小到大排序,对于编号为偶数的块,我们用右边界从大到小排序。

这样会快一点,因为不加优化之前来到新的块右端点需要先回溯至这个块里最小的右端点。

但是加了这个优化,有时我们可以从原先的最右边从右往左依次处理新的块的询问,所以会快一点。

代码实现

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const LL N=2e5+5;
struct node
{
	LL l,r,id;
}b[N];
LL n,q,B,a[N],cnt[N],ans[N],sum;
bool cmp(node x,node y)
{
	if(x.l/B==y.l/B)
	{
		if((x.l/B)&1)return x.r<y.r;
		return x.r>y.r;
	}
	return x.l/B<y.l/B;
}
void del(LL x)
{
	cnt[a[x]]--;
	sum-=cnt[a[x]]*(cnt[a[x]]-1)/2;
}
void ins(LL x)
{
	sum+=cnt[a[x]]*(cnt[a[x]]-1)/2;
	cnt[a[x]]++;
}
int main()
{
	scanf("%lld%lld",&n,&q);
	B=sqrt(n);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
	}
	for(int i=1;i<=q;i++)
	{
		scanf("%lld%lld",&b[i].l,&b[i].r);
		b[i].id=i;
	}
	sort(b+1,b+q+1,cmp);
	LL l=1,r=0,sl,sr;
	for(int i=1;i<=q;i++)
	{
		sl=b[i].l,sr=b[i].r;
		while(l<sl)del(l++);
		while(sl<l)ins(--l);
		while(r<sr)ins(++r);
		while(sr<r)del(r--);
		ans[b[i].id]=sum;
	}
	for(int i=1;i<=q;i++)
	{
		printf("%lld\n",ans[i]);
	}
}

标签:cnt,复杂度,sqrt,学习,leq,笔记,莫队,LL
From: https://www.cnblogs.com/dengduck/p/17519968.html

相关文章

  • 英语学习0624
    1.beworthdoing:值得做某事2.putup张贴3.acrossfrom在....对面4.let`s+动词原型5.howabout+doing做某事怎么样?6.whatistheweatherliketoday?今天天气怎么样7.setoff动身8.putoff推迟9.getaway逃离10.takeaway拿走11.runaway逃跑12.comeout出版,发......
  • t113-c-dts学习篇2
    dts的makefile我们来到dts的makefile查看一下我们的板子所编译的代码,此代码表示如果sun8iw20就添加生成board.dtb,可能是因为这个变量还有其他参数吧所以用+=对于cell的更新补充其实这款i的cells都是指用多少位来表示地址和大小,并且单位是bytesdts和dtsi的共同跟文件dts和dt......
  • atx-agent学习(1)-怎么判断是否安装了atx-agent
    atx-agent是运行在手机上的一个代理程序,可以通过网络进行手机测试,项目地址:https://github.com/openatx/atx-agent通过阅读uiautomator2源码,搞明白了判断的过程,有如下心得:安装adbutils库,建立Device对象,下面的代码可以获取atx_agent可执行文件是否存在atx_agent......
  • 暑假Java学习第一周
    6.25先跟着黑马了解认识了一下Java的历史、现状、火爆的原因等。然后开始正式学习Java的编程。安装Oracle的JDK在电脑上配置环境变量,下载之后自动配置完成。然后编写HelloWorld.java程序,win+r——cmd调用命令面板来编译程序,但是未运行成功。具体问题是javac运行不报错(并且没有......
  • Vim学习笔记2--录制宏,调用宏
    1.VIM编辑器--录制宏调用宏录制宏qa进入宏记录模式,a为宏名shift+w移到词首i.escshift+ei()escq退出宏记录调用宏@a使用宏名为a的宏@前加数字表示重复操作的次数 2.VIM编辑器--文本替换r替换:1,$s;a;b;gc(:1,$sa;b;gc)高级进阶用法:100,200s/1/2/gc含义:vim......
  • C语言笔记:第3章 数据和C
    C语言中,数据类型可以分为基本数据类型、构造数据类型、指针数据类型、空类型四大类: 基本类型介绍如下: 整型数据是指不带小数的数字(int,shortint,longint,unsignedint,unsignedshortint,unsignedlongint):  转义列表: ......
  • 【狂神说Java】Java零基础学习笔记-预料
    【狂神说Java】Java零基础学习笔记-预料预料01:学习准备:博客博客,英文名为Blog,它的正式名称为网络日记为什么要写博客?需要总结和思考。有时候我们一直在赶路,却忘了放慢脚步提升文笔组织能力提升学习总结能力提升逻辑思维能力帮助他人,结交朋友冰冻三尺非一日之寒,写......
  • 众所周知,梯度下降法是一种基本的优化算法,不能保证全局最优,也不能保证效率。为什么它仍
    梯度下降法在深度学习中被广泛应用的原因主要有以下几点:适用性广泛:梯度下降法可以应用于各种深度学习模型,包括神经网络、卷积神经网络、循环神经网络等。而传统的凸优化算法和粒子群算法往往只适用于特定类型的优化问题。原理简单:梯度下降法的原理相对简单,易于理解和实现。......
  • 第二周笔记
     ......
  • Linux学习笔记
    Linux命令ls 查看文件夹下的文件cd 切换路径pwd 查看当前所在的路径位置.. 上层目录mkdir 创建文件夹touch 创建文件且要指定后缀cat 查看文件内容more 查看文件内容(支持翻页[没试过])rm 删除文件 (删除文件夹使用rm-r)cp 复制文件rm 移动文件(移动文件谨慎使......