【洛谷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上数据强一些? 分析: 这题真的是--一言难尽 发现题面里没说权值的范围,怕出锅就写了离散化.后来经过面向数据编程(以及膜神犇代码)知道 ...
随机推荐
- 20190608_浅谈go&java差异(三)
20190608_浅谈go&java差异(三) 转载请注明出处https://www.cnblogs.com/funnyzpc/p/10990703.html 第三节内容概览 多线程通讯(线程 ...
- idea中git分支、合并与使用
1.分支的新建与合并使用场景介绍 让我们来看一个简单的分支新建与分支合并的例子,实际工作中你可能会用到类似的工作流. 你将经历如下步骤: 开发某个网站. 为实现某个新的需求.问题(#53问题),创建一 ...
- 11G-使用跨平台增量备份减少可移动表空间的停机时间 XTTS (Doc ID 1389592.1)
11G - Reduce Transportable Tablespace Downtime using Cross Platform Incremental Backup (Doc ID 13895 ...
- pycharm报错:Process finished with exit code -1073741819 (0xC0000005)解决办法
这个是几个月前的问题了,有小伙伴在CSDN问我咋解决的,那我今天在这边把这个问题解决办法分享下吧,免得大家把很多时间都浪费在安装排坑上面,有些坑虽然解决了还真不知道啥原因. 我的pycharm一直用的 ...
- linux 常用命令及软件
命令基于ubuntu 18.04 修改网卡配置 /etc/netplan/50-cloud-init.yaml #修改 netplan apply #应用修改 修改计算机名 sudo hostname ...
- 如何给女朋友讲明白:Java 中 Stack(栈) 与 Heap(堆)
背景 Java 中 Stack(栈) 与 Heap(堆) 是面试中被经常问到的一个话题. 有没有对 Java 中 Stack(栈) 与 Heap(堆) 烂熟于心的童鞋,请举手!!!(怎么没人举手-) ...
- Java题库——Chapter3 操作符、选择
1)The "less than or equal to" comparison operator in Java is ________. A)<< B) != C) ...
- ubuntu18.04 安装 QQ
参照大佬文章https://www.lulinux.com/archives/1319 我将安装过程需要的命令行总结出来,便于直接快速安装. # 安装 wine git clone https://g ...
- 微信公众号支付提示当前页面的URL未注册
问题: 记一下前端时间自己做了一个微信公众号支付的功能,因为有一段时间没有接触过了微信支付方面的开发,居然忘记了在微信商户商户号中配置了对应的支付目录,所以提示我当前的域名是没有注册的. 设置支付目录 ...
- PHP+Ajax实现文章心情投票功能实例
一个PHP+Ajax实现文章心情投票功能实例,可以学习了解实现投票的基本流程:通过ajax获取心情图标及柱状图相关数据,当用户点击其中的一个心情图标时,向Ajax.php发送请求,PHP验证用户coo ...