【洛谷5072】[Ynoi2015] 盼君勿忘(莫队)
大致题意: 一个序列,每次询问一个区间\([l,r]\)并给出一个模数\(p\),求模\(p\)意义下区间\([l,r]\)内所有子序列去重后值的和。
题意转化
原来的题意看起来似乎很棘手,因此需要一定的转化。
考虑一个值\(x\)的贡献,设它在区间中出现的次数为\(cnt_x\),则共有\(2^{r-l+1}-2^{r-l+1-cnt_x}\)个子序列中有这个值,因此它的贡献就是\(x\cdot (2^{r-l+1}-2^{r-l+1-cnt_x})\)。
经这么一转化,不难发现,要求出这个式子的值,我们需要高效维护出区间内每个数的出现次数。
怎么维护呢?结合题目来源是Ynoi,我们不难想到莫队。
计算答案
通过莫队,我们能够在\(O(n\sqrt n)\)的时间内轻松求出\(cnt_x\)。
但必须要注意此题最大的坑点,因为模数是由询问给出的,所以我们无法直接维护答案中\(2\)的幂。
那么,我们就需要考虑,如何在维护\(cnt_x\)的基础上,对于每个询问,在\(O(\sqrt n)\)的时间内快速计算出答案。
研究\(x\cdot (2^{r-l+1}-2^{r-l+1-cnt_x})\)这个式子,可以发现在\(cnt\)相等时,后面\(2\)的幂是相同的,因此我们可以想到设\(sum_i=\sum_{cnt_x=i} x\),则答案就是\(\sum sum_i\cdot(2^{r-l+1}-2^{r-l+1-i})\)。
\(sum_i\)可以在维护\(cnt_x\)的时候一同维护,但如果我们求答案时真的去枚举\(i\),复杂度依然是\(O(n)\)。
所以我们可以考虑设阈值:
- 对于\(cnt_x\le\sqrt n\),我们直接枚举这\(\sqrt n\)个\(sum_i\)计算答案,单次询问复杂度为\(O(\sqrt n)\)。
- 对于\(cnt_x>\sqrt n\),由于\(\sum cnt_x=r-l+1\le n\),因此这样的\(x\)不超过\(\sqrt n\)个,可以在莫队同时用链表维护,然后询问时扫描链表计算答案,单次询问复杂度为\(O(\sqrt n)\)。
这样一来复杂度就做到了\(O(n\sqrt n)\)。
预处理\(2\)的幂——真正的\(O(n\sqrt n)\)
注意,如果用快速幂来求\(2\)的幂,显然,会让复杂度多带一个\(log\),这就让原本已经较高的复杂度更是难以接受,因此需要想办法去掉这个\(log\)。
怎样才能做到呢?很简单,其实预处理一下就可以了。
由于模数是询问中给出的,所以我们需要对于每个询问\(O(\sqrt n)\)预处理出\(2\)的幂。
实际上,我们只需预处理\(p2_i=2^i,p1_i=2^{i\sqrt n}\),然后就能实现\(O(\sqrt n)\)预处理、\(O(1)\)计算了。
代码
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
using namespace std;
int n,Bs,Qt,a[N+5];
struct Query
{
int l,r,X,p,bl;I Query(CI x=0,CI y=0,CI g=0,CI i=0):l(x),r(y),X(g),p(i){Bs&&(bl=(x-1)/Bs+1);}
I bool operator < (Con Query& o) Con {return bl^o.bl?bl<o.bl:(bl&1?r<o.r:r>o.r);}
}q[N+5];
I int Qpow(RI x,RI y,RI X) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
class FastIO
{
private:
#define FS 100000
#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
#define pc(c) (C==E&&(clear(),0),*C++=c)
#define tn (x<<3)+(x<<1)
#define D isdigit(c=tc())
int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
public:
I FastIO() {A=B=FI,C=FO,E=FO+FS;}
Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
Tp I void writeln(Con Ty& x) {write(x),pc('\n');}
I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
}F;
class MoQueueSolver
{
private:
#define P(x) (1LL*p1[(x)/Bs]*p2[(x)%Bs]%X)//计算2的幂
#define Ins(x) (nxt[x]=lnk,lst[lnk]=x,lnk=x)//链表中插入
#define Kill(x) ((x)^lnk?(lst[nxt[x]]=lst[x],nxt[lst[x]]=nxt[x]):(lnk=nxt[x]))//链表中删除
#define Add(x) cnt[x]==Bs&&Ins(x),cnt[x]<=Bs&&(sum[cnt[x]]-=x),++cnt[x]<=Bs&&(sum[cnt[x]]+=x)//加入元素
#define Del(x) cnt[x]==Bs+1&&Kill(x),cnt[x]<=Bs&&(sum[cnt[x]]-=x),--cnt[x]<=Bs&&(sum[cnt[x]]+=x)//删除元素
int X,ans[N+5],p1[N+5],p2[N+5],cnt[N+5],lnk,lst[N+5],nxt[N+5];long long sum[N+5];
I int Qry(CI l,CI r)//询问答案
{
RI i,p=P(r-l+1),t=0;for(i=1;i<=Bs;++i) t=(1LL*(p-P(r-l+1-i)+X)*(sum[i]%X)+t)%X;//对于小于等于sqrt(n)的部分
for(i=lnk;i;i=nxt[i]) t=(1LL*i*(p-P(r-l+1-cnt[i])+X)+t)%X;return t;//对于大于sqrt(n)的部分
}
public:
I void Solve()
{
RI i,j,L=1,R=0;for(sort(q+1,q+Qt+1),i=1;i<=Qt;++i)//莫队
{
W(R<q[i].r) ++R,Add(a[R]);W(L>q[i].l) --L,Add(a[L]);
W(R>q[i].r) Del(a[R]),--R;W(L<q[i].l) Del(a[L]),++L;
for(X=q[i].X,p1[0]=p2[0]=j=1;j<=Bs;++j) p2[j]=(p2[j-1]<<1)%X;//预处理2的幂
for(j=1;j<=(q[i].r-q[i].l+1)/Bs;++j) p1[j]=1LL*p1[j-1]*p2[Bs]%X;
ans[q[i].p]=Qry(q[i].l,q[i].r);//求解并记下答案
}
for(i=1;i<=Qt;++i) F.writeln(ans[i]);//输出答案
}
}M;
int main()
{
RI i,x,y,z;for(F.read(n),F.read(Qt),Bs=sqrt(n),i=1;i<=n;++i) F.read(a[i]);
for(i=1;i<=Qt;++i) F.read(x),F.read(y),F.read(z),q[i]=Query(x,y,z,i);//读入并存储询问
return M.Solve(),F.clear(),0;
}
【洛谷5072】[Ynoi2015] 盼君勿忘(莫队)的更多相关文章
- 洛谷P5072 [Ynoi2015]盼君勿忘 [莫队]
传送门 辣鸡卡常题目浪费我一下午-- 思路 显然是一道莫队. 假设区间长度为\(len\),\(x\)的出现次数为\(k\),那么\(x\)的贡献就是\(x(2^{len-k}(2^k-1))\),即 ...
- 洛谷:P5072 [Ynoi2015]盼君勿忘
原题地址:https://www.luogu.org/problem/P5072 题目简述 给定一个序列,每次查询一个区间[l,r]中所有子序列分别去重后的和mod p 思路 我们考虑每个数的贡献.即 ...
- [Ynoi2015]盼君勿忘
题目大意: 给定一个序列,每次查询一个区间\([l,r]\)中所有子序列分别去重后的和\(\bmod p\)(每次询问模数不同). 解题思路: 在太阳西斜的这个世界里,置身天上之森.等这场战争结束之后 ...
- 【题解】Luogu P5072 [Ynoi2015]盼君勿忘
众所周知lxl是个毒瘤,Ynoi道道都是神仙题,题面好评 原题传送门 一看这题没有修改操作就知道这是莫队题 我博客里对莫队的简单介绍 既然是莫队,我们就要考虑每多一个数或少一个数对答案的贡献是什么 假 ...
- P5072 [Ynoi2015]盼君勿忘
传送门 一开始理解错题意了--还以为是两个子序列相同的话只算一次--结果是子序列里相同的元素只算一次-- 对于一个区间\([l,r]\),设其中\(x\)出现了\(k\)次,那么它的贡献就是它的权值乘 ...
- Luogu5072 [Ynoi2015]盼君勿忘 【莫队】
题目描述:对于一个长度为\(n\)的序列,\(m\)次询问\(l,r,p\),计算\([l,r]\)的所有子序列的不同数之和\(\mathrm{mod} \ p\). 数据范围:\(n,m,a_i\l ...
- Luogu P5072 [Ynoi2015]盼君勿忘
题意 给定一个长度为 \(n\) 的序列 \(a\) 和 \(m\) 次询问,第 \(i\) 次询问需要求出 \([l_i,r_i]\) 内所有子序列去重之后的和,对 \(p_i\) 取模. \(\t ...
- Bzoj2038/洛谷P1494 小Z的袜子(莫队)
题面 Bzoj 洛谷 题解 考虑莫队算法,首先对询问进行分块(分块大小为\(sqrt(n)\)),对于同一个块内的询问,按照左端点为第一关键字,右端点为第二关键字排序.我们统计这个区间内相同的颜色有多 ...
- 【洛谷4396/BZOJ3236】[AHOI2013]作业(莫队+分块/树状数组/线段树)
题目: 洛谷4396 BZOJ3236(权限) 这题似乎BZOJ上数据强一些? 分析: 这题真的是--一言难尽 发现题面里没说权值的范围,怕出锅就写了离散化.后来经过面向数据编程(以及膜神犇代码)知道 ...
随机推荐
- arcgis api for javascript 学习(七) 调用发布地图信息,并将地图属性信息输出到Excel表格---进阶版
我们在arcgis api for javascript 学习(三)已经学习到了关于调用地图信息进行属性输出的问题,不过通过代码我们实现后会发现还是有一些小瑕疵的,比如我们只能单个数据属性的输出,如果 ...
- http模块
1.引入http模块 const http = require('http') 2.创建node服务器 在创建node服务器的时候需要使用http模块中的http.creatServer()方法来进行 ...
- linux上安装jenkins过程
最近在学到jenkins分布式构建时,需要一台部署jenkins的主机服务器master,自己用的win10作为slave,所以我想在虚拟机上先部署jenkins. centos还是ubuntu呢,算 ...
- vue 路由对象
路由对象在使用了 vue-router 的应用中,路由对象会被注入每个组件中,赋值为 this.$route ,并且当路由切换时,路由对象会被更新. so , 路由对象暴露了以下属性: 1.$rout ...
- Oracle 11gR2中HR用户安装说明
1.脚本下载: 链接: 1,脚本放在这个目录下$ORACLE_HOME/demo/schema/human_resources hr_analz.sql hr_code.sq ...
- 关于中医的一段对话 [ZZ] -- 思维训练故事
转载自新浪博客 网址: http://blog.sina.cn/dpool/blog/s/blog_9880df4201015khq.html?type=-1 关于中医的一段对话 2013-01-26 ...
- [读论文]Shading-aware multi view stereo
如何实现refine的? 几何误差和阴影误差如何加到一起? 为了解决什么问题? 弱纹理或无纹理:单纯的多视图立体算法在物体表面弱纹理或者无纹理区域重建完整度不够高,精度也不够高,因此结合阴影恢复形状来 ...
- C语言程序设计100例之(19):欢乐的跳
例19 欢乐的跳 题目描述 一个n个元素的整数数组,如果数组两个连续元素之间差的绝对值包括了[1,n-1]之间的所有整数,则称之符合“欢乐的跳”,如数组1 4 2 3符合“欢乐的跳”,因为差的绝对 ...
- Linux查看CPU和内存情况
本文简单介绍在Linux上查看CPU和内存情况和一款系统资源查看工具htop. 查看CPU情况 以下是个人工作会经常使用到的服务器的信息. 查看所有CPU信息 可以通过如下命令查看所有CPU信息: # ...
- freemarker从入门到精通
目录 一:概述 二:Freemarker的Helloworld 三:freemarker模板语法 1.访问map中的key 2.访问POJO中的属性 3.取集合中的数据 4.判断 5.日期 6.Nul ...