洛谷: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数据分析之Pandas读写外部数据文件
1 引言 数据分析.数据挖掘.可视化是Python的众多强项之一,但无论是这几项中的哪一项都必须以数据作为基础,数据通常都存储在外部文件中,例如txt.csv.excel.数据库.本篇中,我们来捋一捋 ...
- BZOJ3170 [Tjoi2013]松鼠聚会 切比雪夫距离 - 曼哈顿距离 - 前缀和
BZOJ3170 题意: 有N个小松鼠,它们的家用一个点x,y表示,两个点的距离定义为:点(x,y)和它周围的8个点即上下左右四个点和对角的四个点,距离为1.现在N个松鼠要走到一个松鼠家去,求走过的最 ...
- POJ - 3660 Cow Contest 传递闭包floyed算法
Cow Contest POJ - 3660 :http://poj.org/problem?id=3660 参考:https://www.cnblogs.com/kuangbin/p/31408 ...
- 计蒜客 蓝桥杯模拟 瞬间移动 dp
在一个 n \times mn×m 中的方格中,每个格子上都有一个分数,现在蒜头君从 (1,1)(1,1) 的格子开始往 (n, m)(n,m) 的格子走.要求从 (x_1,y_1)(x1,y1 ...
- lightoj 1061 - N Queen Again(状压dp)
题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1061 题解:显然能满足情况的8皇后的摆法不多,于是便可以用题目给出的状态来匹配 ...
- 牛客多校第十场 A Rikka with Lowbit 线段树
链接:https://www.nowcoder.com/acm/contest/148/A来源:牛客网 题目描述 Today, Rikka is going to learn how to use B ...
- CF1003D Coins and Queries 贪心
Coins and Queries time limit per test 2 seconds memory limit per test 256 megabytes input standard i ...
- android CTS 介绍
[转]http://blog.csdn.net/pugongying1988/article/details/6976091 一.为什么需要兼容性测试(以下称CTS)? 1.1.让APP提供更好的用户 ...
- Oracle 11g Rac 用rman实现把本地数据文件迁移到ASM共享存储中
在Oracle Rac环境中,数据文件都是要存放在ASM共享存储上的,这样两个节点才能同时访问.而当你在某一节点下把数据文件创建在本地磁盘的时候,那么在另一节点上要访问该数据文件的时候就会报错,因为找 ...
- springBoot异常统一处理
springBoot异常统一处理 采用@ControllerAdvice注解和@ExceptionHandler注解,可以对异常进行统一处理. 1.结构图: 2.pom.xml文件: <?xml ...