题解 P5072 【[Ynoi2015] 盼君勿忘】
在太阳西斜的这个世界里,置身天上之森。等这场战争结束之后,不归之人与望眼欲穿的众人, 人人本着正义之名,长存不灭的过去、逐渐消逝的未来。我回来了,纵使日薄西山,即便看不到未来,此时此刻的光辉,盼君勿忘。————世界上最幸福的女孩
珂朵莉最最最最最最最珂爱了!
闲话少说,切入正题
第一道 Ynoi&400 题祭
害怎么又暴露自己的菜鸡水平了
显然,\(1\le n,m,a_i \le 10^5\) 这样友好的数据,没有修改的良心操作和可以离线的痕迹,这很显然是个莫队。
但是我们会发现“子序列”“去重”这些东东不好计算,我们转化成贡献。
设 \([l,r]\) 这个区间内有一个 \(x\),这个 \(x\) 又出现了 \(k\) 次,我们来计算 \(x\) 对于 \([l,r]\) 的贡献。
很显然,\([l,r]\) 有 \(2^{r-l+1}\) 个子序列,因为每个元素只有两种状态:选或不选,那么不包含 \(x\) 的子序列有多少个呢?显然就有 \(2^{r-l+1-k}\) 个,由此,我们将两个相减就能得到包含 \(x\) 的子序列个数:\(2^{r-l+1}-2^{r-l+1-k}\) 就是包含 \(x\) 的子序列个数。所以 \(x\) 的贡献就是 \(x\times (2^{r-l+1}-2^{r-l+1-k})\)。
设 \(sum_i\) 为出现次数为 \(i\) 的和,\(cnt_i\) 为 \(i\) 数出现的次数。
然后我们需要一个 DS 来维护一串数量,这些数量为一个数出现的个数,需要支持快速遍历,插入和删除,显然可以用双向链表来维护。
然后我们就可以用莫队来维护这个 \(sum_i\),在插入删除时维护数量链表,最后遍历链表然后根据上面的贡献公式直接累加就好了~
还有一个问题,就是该题中我们要多次计算二的次幂,然而鹅快速幂是 \(\log_2 n\) 的,这该怎么办?
黑科技光速幂出现了!
光速幂是什么?就是预处理 \(2^0\) 到 \(2^{\sqrt n}\) 和 \(2^{\sqrt n},2^{2\times {\sqrt{n}}},2^{3\times {\sqrt{n}}}...2^n\),每个幂次我们都把它看成两个部分相乘就可以 \(O(1)\) 计算啦~
还有一个重要的事情:
能用 \(a_i+a_i\),不用 \(a_i\times2\)
对于我这样并不怎么卡过常的蒟蒻来说这很重要,不然乘 2 试试就逝世/dk
上代码!
#include<cstdio>
#include<algorithm>
#include<cmath>
#define MAXN 100010
#define int long long//这道题的常数不怎么卡,可以这样写
using namespace std;
int n,m,len;
struct node{//莫队输入
int l,r,cl,ind,k;
}in[MAXN];
inline int read()//快读
{
int ans=0;
char ch=getchar();
while (ch<'0' || ch>'9') ch=getchar();
while (ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
return ans;
}
inline void write(int x)
{
char f[200];
int tmp=x>0?x:-x,cnt=0;
if(x==0)putchar('0'),putchar('\n');
else{
if(x<0)putchar('-');
while(tmp>0)f[cnt++]=tmp%10+'0',tmp/=10;
while(cnt>0)putchar(f[--cnt]);
putchar('\n');
}
}
struct list{//手写双向链表
int pre[MAXN],nxt[MAXN],tot;
void insert(int x){nxt[tot]=x,pre[x]=tot,tot=x;}
void erase(int x)
{
if(x!=tot)nxt[pre[x]]=nxt[x],pre[nxt[x]]=pre[x];
else nxt[pre[x]]=0,tot=pre[x];
pre[x]=nxt[x]=0;
}
}ML;
bool cmp(node &x,node &y)//莫堆排序
{
return ((x.cl!=y.cl)?(x.l<y.l):((x.cl&1)?(x.r<y.r):(x.r>y.r)));
}
int sum[MAXN],cnt[MAXN],a[MAXN],p1[MAXN],p2[MAXN],ans[MAXN];
void get(int mod)//光速幂预处理
{
p1[0]=p2[0]=1;
for(int p=1;p<=len+7;p++)
p1[p]=(p1[p-1]+p1[p-1])%mod;
for(int p=1;p<=n/len+7;p++)
p2[p]=p2[p-1]*p1[len]%mod;
}
int Pow(int k,int mod){return p2[k/len]*p1[k%len]%mod;}//光速幂
void add(int qwq)//莫队插入
{
sum[cnt[qwq]]-=qwq;
if(!sum[cnt[qwq]])
ML.erase(cnt[qwq]);
cnt[qwq]++;
if(!sum[cnt[qwq]])
ML.insert(cnt[qwq]);
sum[cnt[qwq]]+=qwq;
}
void del(int qwq)//莫队删除
{
sum[cnt[qwq]]-=qwq;
if(!sum[cnt[qwq]])
ML.erase(cnt[qwq]);
cnt[qwq]--;
if(!sum[cnt[qwq]])
ML.insert(cnt[qwq]);
sum[cnt[qwq]]+=qwq;
}
signed main()
{
n=read(),m=read();
len=sqrt(n);
for(int p=1;p<=n;p++)
a[p]=read();
for(int p=1;p<=m;p++)
{
in[p].l=read(),in[p].r=read(),in[p].k=read();
in[p].ind=p,in[p].cl=(in[p].l-1)/len+1;
}
sort(in+1,in+m+1,cmp);
int l=1,r=0;
for(int p=1;p<=m;p++)
{
get(in[p].k);
while(l<in[p].l)del(a[l++]);
while(l>in[p].l)add(a[--l]);
while(r<in[p].r)add(a[++r]);
while(r>in[p].r)del(a[r--]);
for(int i=ML.nxt[0];i;i=ML.nxt[i])
ans[in[p].ind]=(ans[in[p].ind]+((sum[i]*(Pow(in[p].r-in[p].l+1,in[p].k)-Pow(in[p].r-in[p].l+1-i,in[p].k)))%in[p].k+in[p].k)%in[p].k+in[p].k)%in[p].k;//然后是统计贡献,记得取模
}
for(int p=1;p<=m;p++)
write(ans[p]);//输出
}
PS:这份代码不能保证随时随地每时每刻都能 AC 这道题,因为最长的点跑了 3s,很可能评测姬任务一多然后就炸开花了
题解 P5072 【[Ynoi2015] 盼君勿忘】的更多相关文章
- 【题解】Luogu P5072 [Ynoi2015]盼君勿忘
众所周知lxl是个毒瘤,Ynoi道道都是神仙题,题面好评 原题传送门 一看这题没有修改操作就知道这是莫队题 我博客里对莫队的简单介绍 既然是莫队,我们就要考虑每多一个数或少一个数对答案的贡献是什么 假 ...
- 洛谷:P5072 [Ynoi2015]盼君勿忘
原题地址:https://www.luogu.org/problem/P5072 题目简述 给定一个序列,每次查询一个区间[l,r]中所有子序列分别去重后的和mod p 思路 我们考虑每个数的贡献.即 ...
- Luogu P5072 [Ynoi2015]盼君勿忘
题意 给定一个长度为 \(n\) 的序列 \(a\) 和 \(m\) 次询问,第 \(i\) 次询问需要求出 \([l_i,r_i]\) 内所有子序列去重之后的和,对 \(p_i\) 取模. \(\t ...
- 洛谷P5072 [Ynoi2015]盼君勿忘 [莫队]
传送门 辣鸡卡常题目浪费我一下午-- 思路 显然是一道莫队. 假设区间长度为\(len\),\(x\)的出现次数为\(k\),那么\(x\)的贡献就是\(x(2^{len-k}(2^k-1))\),即 ...
- P5072 [Ynoi2015]盼君勿忘
传送门 一开始理解错题意了--还以为是两个子序列相同的话只算一次--结果是子序列里相同的元素只算一次-- 对于一个区间\([l,r]\),设其中\(x\)出现了\(k\)次,那么它的贡献就是它的权值乘 ...
- [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 ...
- EC笔记:第二部分:12、复制对象时勿忘其每一个成分
EC笔记:第二部分:12.复制对象时勿忘其每一个成分 1.场景 某些时候,我们不想使用编译器提供的默认拷贝函数(包括拷贝构造函数和赋值运算符),考虑以下类定义: 代码1: class Point{ p ...
- EC读书笔记系列之7:条款12 复制对象时勿忘其每一个成分
记住: ★copying函数应确保复制“对象内的所有成员变量”及“所有base class成分” ★不要尝试以某个copying函数实现另一个copying函数.应该将共同机能放进第三个函数中,并由两 ...
随机推荐
- Mybatis04:延迟加载、一二级缓存、注解开发
今日内容 mybatis中的延迟加载 延迟加载的概念 立即加载的概念 如果实现延迟加载 Mybatis中的缓存 什么是缓存 为什么使用缓存 什么数据可以使用缓存,什么样的数据不能使用缓存 Mybati ...
- 提高python异步效率
uvloop #Python标准库中提供了asyncio模块,用于支持基于协程的异步编程. #uvloop是 asyncio 中的事件循环的替代方案,替换后可以使得asyncio性能提高.事实上,uv ...
- SpringBoot源码2——SpringBoot x Mybatis 原理解析(如何整合,事务如何交由spring管理,mybatis如何进行数据库操作)
阅读本文需要spring源码知识,和springboot相关源码知识 对于springboot 整合mybatis,以及mybatis源码关系不密切的知识,本文将简单带过 系列文章目录和关于我 涉及到 ...
- 关于如何在C#中调用C++的DLL,以及如何在C++中调用C#的DLL
一.关于如何在C#中调用C++的DLL,以及如何在C++中调用C#的DLL 注:clr指公共语言运行库 CLR是一门非常恶搞的语言,就好像是在C++里面写C#的文件一样,也就是一种所谓的"托 ...
- 实现 .Net 7 下的数据库定时检查
在软件开发过程中,有时候我们需要定时地检查数据库中的数据,并在发现新增数据时触发一个动作.为了实现这个需求,我们在 .Net 7 下进行一次简单的演示. PeriodicTimer .Net 6 中新 ...
- 利用Git同步思源笔记
旧文章从语雀迁移过来,原日期为2022-10-22 思源笔记是一款优秀的本地优先的双链大纲笔记软件,拥有强大的笔记编辑功能且都是免费,唯一付费的就是云同步等一些服务了.但如果暂时还用不着云同步的,我们 ...
- [LeetCode]226.翻转二叉树——递归遍历交换孩子
题目 翻转一棵二叉树. 4 / \ 2 7 / \ / \ 1 3 6 9 //转换为: 4 / \ 7 2 / \ / \ 9 6 3 1 代码 TreeNode* invertTree(Tre ...
- 關於scanf()的使用
要使用scanf函數進行輸入: 1.如果用scanf()要輸入讀取基本變量的值,需要加&. 2.如果用scanf()讀取的是把字符串讀入字符數組中,則不需要加& 1 #include& ...
- angular打包部署设置publicPath文件目录及访问地址,解决打包完成后,运行打包文件,报错404,js,css未找到
方案1.改变文件目录 不改变访问地址:XXXPRO 是部署的服务器上面的 文件夹名称 ng build --prod --base-href /XXXPRO 方案2.改变访问地址录同时改变文件目录-- ...
- 1.MAC获取文件路径;2.MAC使用SSH连接远程服务器,实现文件上传下载
首先来说一下如何获取文件路径 ····打开terminal,把文件拖进terminal 窗口,自动显示路径. 接下来说一下使用SSH连接远程服务器,实现文件上传下载 1. 上传本地文件到服务器 sc ...