洛谷:P5072 [Ynoi2015]盼君勿忘
原题地址:https://www.luogu.org/problem/P5072
题目简述
给定一个序列,每次查询一个区间[l,r]中所有子序列分别去重后的和mod p
思路
我们考虑每个数的贡献。即该区间内含有这个数的子序列个数。用补集转化为不含这个数的子序列个数。
那么,假设这个数在[l,r]内出现了kk次,则一共有2(r-l+1)-2(r-l+1-k)个子序列包含这个数。
本题可以离线,因此选择使用莫队,过程中维护cnt[k]表示区间内恰好出现k次的数字个数,维护sum[j]表示区间内恰好出现j次的数字之和(区间内出现次数相同的数,对于这些数,区间中包含这些数的子序列个数都相同,因此存数字之和就行)。
然而这样时间复杂度为O(询问次数*单次询问复杂度)=O(n*max(sqrt(n),n))=O(nm),并不可行。我们发现时间瓶颈不在莫队的sqrt(n),而是在单次查询中求解的复杂度n。
有2个套路可供使用:出现次数大于sqrt(n)的数不超过sqrt(n)个,值不为0的cnt[k]少于2*sqrt(n)个(反证易得,本质类似)。
- 对于第一个套路,我们分类讨论:出现次数小于等于sqrt(n),则统计每个出现次数的数字之和;大于sqrt(n)的用哈希表(unordered_set,C++11)存下具体的数字和其出现次数。这样每次查询是sqrt(n)。
- 笔者使用的则是第二个套路:val[x]表示出现次数恰好为x的数字之和(同上文的sum[j])。随着莫队l,r指针的移动,把所有可能变为非0的val[x]记下来,指针移动完毕后再对其进行筛选,把确实非0的val[x]保留,其他去除。这样计算单次答案的复杂度就等同于单次查询中莫队指针移动的平均步数:都是sqrt(n)级别。这样做不需要用到哈希表之类的,常数小了很多,甚至不需要读入优化也能轻松过。
还没完。我们发现模数是不定的,为了保证单次查询的复杂度压在sqrt(n)以内,我们还有最后一件事情要做:在sqrt(n)的时间内求出2(r-l+1)和所有的2(r-l+1-k)。这里安利一个神奇的方式:每次查询只需要做一次时间复杂度为sqrt(n)的预处理就可以O(1)查询了。
假设查询区间长度为len(len=r-l+1),我们记siz=sqrt(len),而后计算20,21,22...2sqrt(len),存在数组pow1中;再计算2sqrt(len),2(2*sqrt(len)),2(3*sqrt(len)),2(4*sqrt(len))...,2^(sqrt(len)*sqrt(len)),存在数组pow[2]中。以上计算都在mod p意义下进行。
这样求2的任意次方都可以O(1)出解:2k=2(k/siz)*2^(k%siz)=pow2[k/siz]*pow1[k%siz](记得模p)。
代码
#include <bits/stdc++.h>
using namespace std;
#define MAXN 100005
int n,m;
int a[MAXN],val[MAXN*2],cnt[MAXN],ans[MAXN];
int tot,blosiz,powsiz;
int bel[MAXN],pow1[MAXN],pow2[MAXN];
bool calced[MAXN];
long long sum[MAXN];
struct query {
int id,l,r,p;
bool operator<(const query &sb) const {
return bel[l]!=bel[sb.l] ? bel[l]<bel[sb.l] : (bel[l]&1 ? r<sb.r : r>sb.r);
}
} q[MAXN];
void add(int x)
{
sum[cnt[x]]-=x;
cnt[x]++;
sum[cnt[x]]+=x;
++tot;
val[tot]=cnt[x];
}
void del(int x)
{
sum[cnt[x]]-=x;
cnt[x]--;
sum[cnt[x]]+=x;
++tot;
val[tot]=cnt[x];
}
int power(int x,int p)
{
return 1LL*pow1[x%powsiz]*pow2[x/powsiz]%p;
}
int main()
{
scanf("%d%d",&n,&m);
blosiz=sqrt(n);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]),bel[i]=(i-1)/blosiz;
for (int i=1;i<=m;i++)
scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].p),q[i].id=i;
sort(q+1,q+m+1);
int l=1,r=0;
for (int i=1;i<=m;i++) {
while (l>q[i].l) add(a[--l]);
while (r<q[i].r) add(a[++r]);
while (l<q[i].l) del(a[l++]);
while (r>q[i].r) del(a[r--]);
int newtot=0;
int len=r-l+1;
for (int j=1;j<=tot;j++)
if (val[j]&&sum[val[j]]!=0&&!calced[val[j]])
calced[val[j]]=1,val[++newtot]=val[j];
tot=newtot;
powsiz=sqrt(len)+1;
pow1[0]=pow2[0]=1;
for (int j=1;j<=powsiz;j++)
pow1[j]=(pow1[j-1]+pow1[j-1])%q[i].p;
for (int j=1;j*powsiz<=len;j++)
pow2[j]=1LL*pow2[j-1]*pow1[powsiz]%q[i].p;
int powLen=power(len,q[i].p);
for (int j=1;j<=tot;j++) {
long long num=sum[val[j]]%q[i].p;
ans[q[i].id]=(ans[q[i].id]+num*(powLen-power(len-val[j],q[i].p)))%q[i].p;
calced[val[j]]=0;
}
ans[q[i].id]+=q[i].p;
ans[q[i].id]%=q[i].p;
}
for (int i=1;i<=m;i++)
printf("%d\n",ans[i]);
return 0;
}
洛谷:P5072 [Ynoi2015]盼君勿忘的更多相关文章
- 洛谷P5072 [Ynoi2015]盼君勿忘 [莫队]
传送门 辣鸡卡常题目浪费我一下午-- 思路 显然是一道莫队. 假设区间长度为\(len\),\(x\)的出现次数为\(k\),那么\(x\)的贡献就是\(x(2^{len-k}(2^k-1))\),即 ...
- 【题解】Luogu P5072 [Ynoi2015]盼君勿忘
众所周知lxl是个毒瘤,Ynoi道道都是神仙题,题面好评 原题传送门 一看这题没有修改操作就知道这是莫队题 我博客里对莫队的简单介绍 既然是莫队,我们就要考虑每多一个数或少一个数对答案的贡献是什么 假 ...
- P5072 [Ynoi2015]盼君勿忘
传送门 一开始理解错题意了--还以为是两个子序列相同的话只算一次--结果是子序列里相同的元素只算一次-- 对于一个区间\([l,r]\),设其中\(x\)出现了\(k\)次,那么它的贡献就是它的权值乘 ...
- Luogu P5072 [Ynoi2015]盼君勿忘
题意 给定一个长度为 \(n\) 的序列 \(a\) 和 \(m\) 次询问,第 \(i\) 次询问需要求出 \([l_i,r_i]\) 内所有子序列去重之后的和,对 \(p_i\) 取模. \(\t ...
- [Ynoi2015]盼君勿忘
题目大意: 给定一个序列,每次查询一个区间\([l,r]\)中所有子序列分别去重后的和\(\bmod p\)(每次询问模数不同). 解题思路: 在太阳西斜的这个世界里,置身天上之森.等这场战争结束之后 ...
- 【洛谷5072】[Ynoi2015] 盼君勿忘(莫队)
点此看题面 大致题意: 一个序列,每次询问一个区间\([l,r]\)并给出一个模数\(p\),求模\(p\)意义下区间\([l,r]\)内所有子序列去重后值的和. 题意转化 原来的题意看起来似乎很棘手 ...
- Luogu5072 [Ynoi2015]盼君勿忘 【莫队】
题目描述:对于一个长度为\(n\)的序列,\(m\)次询问\(l,r,p\),计算\([l,r]\)的所有子序列的不同数之和\(\mathrm{mod} \ p\). 数据范围:\(n,m,a_i\l ...
- 洛谷P5069 [Ynoi2015]纵使日薄西山(树状数组,set)
洛谷题目传送门 一血祭 向dllxl致敬! 算是YNOI中比较清新的吧,毕竟代码只有1.25k. 首先我们对着题意模拟,寻找一些思路. 每次选了一个最大的数后,它和它周围两个数都要减一.这样无论如何, ...
- 洛谷 P5071 - [Ynoi2015] 此时此刻的光辉(莫队)
洛谷题面传送门 一道其实算得上常规的题,写这篇题解是为了总结一些数论中轻微(?)优化复杂度的技巧. 首先感性理解可以发现该问题强于区间数颜色问题,无法用常用的 log 数据结构维护,因此考虑分块/莫队 ...
随机推荐
- python接口自动化测试之requests库详解
前言 说到python发送HTTP请求进行接口自动化测试,脑子里第一个闪过的可能就是requests库了,当然python有很多模块可以发送HTTP请求,包括原生的模块http.client,urll ...
- 【selenium】- webdriver常见api
本文由小编根据慕课网视频亲自整理,转载请注明出处和作者. 1.常见API 2.打开网址 3.操作浏览器 quit()没有完全关闭进程,依旧占用资源. 4.输入框操作 5.选择框操作 6.特殊窗口操作 ...
- python中,一个函数想使用另一个函数中的变量
问题: 第一个函数中用到了变量a:第二个函数也想使用变量a. 解决方法: 在第一个函数中将变量a定义为全局变量,然后在第二个函数中,也写上global a即可. 示例: def func1(): gl ...
- [普及]NOIP 2015 推销员 贪心
NOIP 2015 推销员 题意: 有一个喜欢疲劳的推销员,告诉你在一个单口胡同(数轴)中的n户家庭的位置,和向他们推销可以获得的疲劳度.分别输出向(1,2,3,4...n)户人家推销可以得到的最大疲 ...
- 这一次,彻底弄懂 Promise 原理
作者声明 本人将迁移至个人公众号「前端Q」及「掘金」平台写文章.博客园的文章将不再及时更新发布.欢迎大家关注公众号「前端Q」及我的掘金主页:https://juejin.im/user/5874526 ...
- 题解 洛谷P5259【欧稳欧再次学车】
实际上没什么可说的,暴力大模拟就好. 一定要开long long! 一定要开long long! 一定要开long long! (不然会炸数据的!!!) //Stand up for the fait ...
- 小白学Python-S3-day04-用户信息的增删改查、变更权限
一.用户信息 文件中每一行就是用户的详细信息,每一行是按照冒号为分隔符分成七段 第一段用户名,第二段密码占位符,第三段UID,第四段GID,第五段是描述信息,第六段是家目录.第七段是 是否 可以登录操 ...
- Storm 系列(四)—— Storm 集群环境搭建
一.集群规划 这里搭建一个 3 节点的 Storm 集群:三台主机上均部署 Supervisor 和 LogViewer 服务.同时为了保证高可用,除了在 hadoop001 上部署主 Nimbus ...
- IPv6地址存储
import java.util.Arrays; /** * @author: 何其有静 * @date: 2019/4/2 * @description: IPv6地址存储 * https://mp ...
- asp.net core 使用 signalR(二)
asp.net core 使用 signalR(二) Intro 上次介绍了 asp.net core 中使用 signalR 服务端的开发,这次总结一下web前端如何接入和使用 signalR,本文 ...