题目大意:

给定一个序列,每次查询一个区间\([l,r]\)中所有子序列分别去重后的和\(\bmod p\)(每次询问模数不同)。

解题思路:

在太阳西斜的这个世界里,置身天上之森。等这场战争结束之后,不归之人与望眼欲穿的众人, 人人本着正义之名,长存不灭的过去、逐渐消逝的未来。我回来了,纵使日薄西山,即便看不到未来,此时此刻的光辉,盼君勿忘。————世界上最幸福的女孩

珂朵莉,要永远幸福哦。

---

我们考虑每个数的贡献。即该区间内含有这个数的子序列个数。用补集转化为不含这个数的子序列个数。

那么,假设这个数在\([l,r]\)内出现了\(k\)次,则一共有\(2^{r-l+1}-2^{r-l+1-k}\)个子序列**包含**这个数。

所以,我们莫队,维护所有出现\(k\)次的不同数的和,然后包含这些数的子序列个数都相同,所以直接用和来计算贡献即可。

时间复杂度\(O(nm)\),非常优秀。

考虑根号内分类讨论。

对于出现次数大于\(\sqrt n\)的数,这种数最多不到\(\sqrt n\)个。

所以我们莫队,统计出现次数小于等于\(\sqrt n\)的所有出现次数为\(i\)的和\(s_i\),然后用一个东西来维护所有出现次数大于\(\sqrt n\)的数。

这样的话,每次询问的复杂度就是\(O(\sqrt n)\)了。

看上去好像没什么问题,实际上你会发现求2的幂次还有个\(\log\),而且模数会改,不好预处理。

有一种分块\(O(\sqrt n)\)预处理,\(O(1)\)求幂次的方法,具体就是求出\(2^0,2^1,2^2,\dots,2^{{\sqrt n}-1}\)和\(2^{\sqrt n},2^{2\sqrt n},\dots,2^n\)(模意义),然后每个幂都分成两部分相乘即可。

每次询问重新计算一遍即可。

然后我们考虑用什么东西来维护出现次数大于\(\sqrt n\)的数。我用了unordered_set,理论上是线性的(当然这个理论有多可靠就不知道了)。

这样总时间复杂度\(O((n+m)\sqrt n)\),空间复杂度\(O(n)\)。

C++ Code:

#include<cstdio>
#include<cctype>
#include<algorithm>
#include<vector>
#include<unordered_set>
#ifdef ONLINE_JUDGE
struct istream{
char buf[23333333],*s;
inline istream(){
buf[fread(s=buf,1,23333330,stdin)]='\n';
fclose(stdin);
}
inline istream&operator>>(int&d){
d=0;
for(;!isdigit(*s);++s);
while(isdigit(*s))
d=(d<<3)+(d<<1)+(*s++^'0');
return*this;
}
}cin;
struct ostream{
char buf[8000005],*s;
inline ostream(){s=buf;}
inline ostream&operator<<(int d){
if(!d){
*s++='0';
}else{
static int w;
for(w=1;w<=d;w*=10);
for(;w/=10;d%=w)*s++=d/w^'0';
}
return*this;
}
inline ostream&operator<<(const char&c){*s++=c;return*this;}
inline void flush(){
fwrite(buf,1,s-buf,stdout);
s=buf;
}
inline~ostream(){flush();}
}cout;
#else
#include<iostream>
using std::cin;
using std::cout;
#endif
#define siz 317
#define N 100005
int n,m,a[N],buc[N],_2[siz+2],__2[siz+2],out[N];
long long bvc[siz+2];
std::vector<int>lr;
std::unordered_set<int>s;
inline int pow2(int b,const int&md){
int ret=1,a=2;
for(;b;b>>=1,a=1LL*a*a%md)
if(b&1)ret=1LL*ret*a%md;
return ret;
}
inline int pw2(int m,const int&md){
return 1LL*_2[m%siz]*__2[m/siz]%md;
}
struct que{
int l,r,id,md;
inline bool operator<(const que&rhs)const{
return(l/siz!=rhs.l/siz)?(l<rhs.l):(r<rhs.r);
}
}q[N];
inline void add(int pos){
const int val=a[pos];
if(buc[val]>siz)++buc[val];else
if(buc[val]==siz)bvc[buc[val]++]-=lr[val],s.insert(val);else
bvc[buc[val]]-=lr[val],bvc[++buc[val]]+=lr[val];
}
inline void del(int pos){
const int val=a[pos];
if(buc[val]>siz+1)--buc[val];else
if(buc[val]==siz+1)s.erase(val),bvc[--buc[val]]+=lr[val];else
bvc[buc[val]]-=lr[val],bvc[--buc[val]]+=lr[val];
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;lr.push_back(a[i++]))cin>>a[i];
std::sort(lr.begin(),lr.end());
for(int i=1;i<=n;++i)a[i]=lower_bound(lr.begin(),lr.end(),a[i])-lr.begin();
for(int i=1;i<=m;++i)
cin>>q[q[i].id=i].l>>q[i].r>>q[i].md;
std::sort(q+1,q+m+1);
int l=1,r=0;
for(int i=1;i<=n;++i)*bvc+=a[i];
*_2=*__2=1;
for(int i=1;i<=m;++i){
while(r<q[i].r)add(++r);
while(l>q[i].l)add(--l);
while(r>q[i].r)del(r--);
while(l<q[i].l)del(l++);
const int md=q[i].md,len=r-l+1;
for(int j=1;j<siz;++j)
_2[j]=2LL*_2[j-1]%md;
__2[1]=pow2(siz,md);
for(int j=2;j<=siz;++j)
__2[j]=__2[1]*1LL*__2[j-1]%md;
int&ans=out[q[i].id];
const int all=pw2(len,md);
for(int j=1;j<=siz;++j)
(ans+=1LL*(all-pw2(len-j,md)+md)*bvc[j]%md-md)+=ans>>31&md;
for(int j:s){
(ans+=1LL*(all-pw2(len-buc[j],md)+md)*lr[j]%md-md)+=ans>>31&md;
}
}
for(int i=1;i<=m;++i)cout<<out[i]<<'\n';
return 0;
}

  

[Ynoi2015]盼君勿忘的更多相关文章

  1. 洛谷P5072 [Ynoi2015]盼君勿忘 [莫队]

    传送门 辣鸡卡常题目浪费我一下午-- 思路 显然是一道莫队. 假设区间长度为\(len\),\(x\)的出现次数为\(k\),那么\(x\)的贡献就是\(x(2^{len-k}(2^k-1))\),即 ...

  2. 【题解】Luogu P5072 [Ynoi2015]盼君勿忘

    众所周知lxl是个毒瘤,Ynoi道道都是神仙题,题面好评 原题传送门 一看这题没有修改操作就知道这是莫队题 我博客里对莫队的简单介绍 既然是莫队,我们就要考虑每多一个数或少一个数对答案的贡献是什么 假 ...

  3. P5072 [Ynoi2015]盼君勿忘

    传送门 一开始理解错题意了--还以为是两个子序列相同的话只算一次--结果是子序列里相同的元素只算一次-- 对于一个区间\([l,r]\),设其中\(x\)出现了\(k\)次,那么它的贡献就是它的权值乘 ...

  4. 洛谷:P5072 [Ynoi2015]盼君勿忘

    原题地址:https://www.luogu.org/problem/P5072 题目简述 给定一个序列,每次查询一个区间[l,r]中所有子序列分别去重后的和mod p 思路 我们考虑每个数的贡献.即 ...

  5. 【洛谷5072】[Ynoi2015] 盼君勿忘(莫队)

    点此看题面 大致题意: 一个序列,每次询问一个区间\([l,r]\)并给出一个模数\(p\),求模\(p\)意义下区间\([l,r]\)内所有子序列去重后值的和. 题意转化 原来的题意看起来似乎很棘手 ...

  6. Luogu5072 [Ynoi2015]盼君勿忘 【莫队】

    题目描述:对于一个长度为\(n\)的序列,\(m\)次询问\(l,r,p\),计算\([l,r]\)的所有子序列的不同数之和\(\mathrm{mod} \ p\). 数据范围:\(n,m,a_i\l ...

  7. Luogu P5072 [Ynoi2015]盼君勿忘

    题意 给定一个长度为 \(n\) 的序列 \(a\) 和 \(m\) 次询问,第 \(i\) 次询问需要求出 \([l_i,r_i]\) 内所有子序列去重之后的和,对 \(p_i\) 取模. \(\t ...

  8. EC笔记:第二部分:12、复制对象时勿忘其每一个成分

    EC笔记:第二部分:12.复制对象时勿忘其每一个成分 1.场景 某些时候,我们不想使用编译器提供的默认拷贝函数(包括拷贝构造函数和赋值运算符),考虑以下类定义: 代码1: class Point{ p ...

  9. EC读书笔记系列之7:条款12 复制对象时勿忘其每一个成分

    记住: ★copying函数应确保复制“对象内的所有成员变量”及“所有base class成分” ★不要尝试以某个copying函数实现另一个copying函数.应该将共同机能放进第三个函数中,并由两 ...

随机推荐

  1. 逆波兰法求解数学表达示(C++)

    主要是栈的应用,里面有两个函数deleteSpace(),stringToDouble()在我还有一篇博客其中:对string的一些扩展函数. 本程序仅仅是主要的功能实现,没有差错控制. #inclu ...

  2. Python游戏server开发日记(一)目标

    到了新的环境.老大让我有空研究下一代server技术,作为一个长期任务. 新的server想达到的目标: 1.分布式系统,对象(Entity)之间的关系类似于Actor模型. 2.逻辑服务,是单进程. ...

  3. Fragment进阶(四)-----&gt;參数传递3种写法

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/ ...

  4. Android源码编译全过程记录(基于最新安卓5.1.0)【转】

    本文转载自:http://blog.csdn.net/drg1612/article/details/44802533 我的编译条件: 1 Ubuntu Kylin 14.04 长期支持版 下载地址 ...

  5. 使用 Swift 3.0 操控日期

    作者:Joe,原文链接,原文日期:2016-09-20译者:Cwift:校对:walkingway:定稿:CMB 当你在想要 大规模重命名 时,一个附带的挑战就是要确保所有相关的文档都必须同步更新.比 ...

  6. C# WINFORM 局域网PING 工具(技术改变世界-cnblog)

    WINFORM 局域网PING 工具(技术改变世界-cnblog) 需求: 1.实时更新 日期时间 2.可以ping多个IP 地址,必须判断 IP地址的正确性,不能为广播地址 3.对ping结果的显示 ...

  7. B1800 [Ahoi2009]fly 飞行棋 数学模拟

    20分钟一遍AC,大水题,我的算法比较复杂,但是好理解,就是找可以凑出来一半周长的点来暴力枚举就行了. 题干: Description 给出圆周上的若干个点,已知点与点之间的弧长,其值均为正整数,并依 ...

  8. sublime 的快捷键大全

    Sublime Text 3 快捷键精华版 Ctrl+Shift+P:打开命令面板 Ctrl+P:搜索项目中的文件 Ctrl+G:跳转到第几行 Ctrl+W:关闭当前打开文件 Ctrl+Shift+W ...

  9. Kubernetes+Jenkins+Nexus+Gitlab进行CI/CD集成

    前面已经完成了 二进制部署Kubernetes集群,下面进行CI/CD集成. 一.流程说明 应用构建和发布流程说明: 1.用户向Gitlab提交代码,代码中必须包含Dockerfile: 2.将代码提 ...

  10. Linux<小白>详细笔记

    目录   应放置的内容 /bin  系统有很多放置执行文件的目录,但是/bin目录比较特殊./bin放置的是在单用户维护模式下还能够被操作的命令.在/bin下面的命令可以被root与一般用户使用. / ...