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

数据范围:\(n,m,a_i\leq 10^5,p\leq 10^9\)

来做做Ynoi中相对简单的题目。。。

首先我们考虑每个数的贡献,如果它出现了\(k\)次,那么会在\(2^{r-l+1}-2^{r-l+1-k}\)个子序列中出现。所以维护\(s[k]\)表示所有出现\(k\)次的数之和,而且\(s[k]\)中不为0的只有\(\sqrt{n}\)个。

所以使用莫队,维护\(s[k]\)并使用hash表维护\(s[k]\)中不为0的个数,并使用光速幂预处理\(2\)的幂次,然后可以\(O(\sqrt{n})\)计算了,时间复杂度\(O((n+m)\sqrt{n})\)。

如果你就这样写了,很容易被卡常,但是根据lxl的数据,hash表可以只维护出现次数\(>\sqrt{n}\)的,然后\([1,\sqrt{n}]\)的直接遍历,这样常数就会小很多。

#include<bits/stdc++.h>
#define Rint register int
using namespace std;
typedef long long LL;
const int N = 100003, mod = 998244353;
inline int kasumi(int a, int b){
int res = 1;
while(b){
if(b & 1) res = (LL) res * a % mod;
a = (LL) a * a % mod; b >>= 1;
}
return res;
}
int n, m, inv[N], root[N << 2], val[N * 350], ls[N * 350], rs[N * 350], cnt;
inline int Add(int a, int b){return (a + b >= mod) ? (a + b - mod) : (a + b);}
inline int Sub(int a, int b){return (a < b) ? (a + mod - b) : (a - b);}
inline int add(int a, int b){return Add((LL) a * Sub(1, b) % mod, (LL) b * Sub(1, a) % mod);}
inline void change(int &x, int L, int R, int l, int r, int v){
if(!x) x = ++ cnt;
if(l <= L && R <= r){val[x] = add(val[x], v); return;}
int mid = L + R >> 1;
if(l <= mid) change(ls[x], L, mid, l, r, v);
if(mid < r) change(rs[x], mid + 1, R, l, r, v);
}
inline int query(int x, int L, int R, int p){
if(!x) return 0;
if(L == R) return val[x];
int mid = L + R >> 1;
if(p <= mid) return add(val[x], query(ls[x], L, mid, p));
else return add(val[x], query(rs[x], mid + 1, R, p));
}
inline void change(int x, int L, int R, int l1, int r1, int l2, int r2, int v){
if(l1 <= L && R <= r1){change(root[x], 1, n, l2, r2, v); return;}
int mid = L + R >> 1;
if(l1 <= mid) change(x << 1, L, mid, l1, r1, l2, r2, v);
if(mid < r1) change(x << 1 | 1, mid + 1, R, l1, r1, l2, r2, v);
}
inline int query(int x, int L, int R, int p1, int p2){
if(L == R) return query(root[x], 1, n, p2);
int mid = L + R >> 1;
if(p1 <= mid) return add(query(root[x], 1, n, p2), query(x << 1, L, mid, p1, p2));
else return add(query(root[x], 1, n, p2), query(x << 1 | 1, mid + 1, R, p1, p2));
}
int main(){
scanf("%d%d", &n, &m);
for(Rint i = 1;i <= n;i ++) inv[i] = kasumi(i, mod - 2);
while(m --){
int opt, l, r;
scanf("%d%d%d", &opt, &l, &r);
if(opt == 1){
if(l > 1){
change(root[0], 1, n, 1, l - 1, 1);
change(1, 1, n, 1, l - 1, l, r, inv[r - l + 1]);
}
if(r < n){
change(root[0], 1, n, r + 1, n, 1);
change(1, 1, n, l, r, r + 1, n, inv[r - l + 1]);
}
if(l < r) change(1, 1, n, l, r, l, r, 2ll * inv[r - l + 1] % mod);
change(root[0], 1, n, l, r, Sub(1, inv[r - l + 1]));
} else if(l == 1) printf("%d\n", Sub(1, query(root[0], 1, n, r)));
else printf("%d\n", Sub(1, query(1, 1, n, l - 1, r)));
}
}

Luogu5072 [Ynoi2015]盼君勿忘 【莫队】的更多相关文章

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

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

  2. [Ynoi2015]盼君勿忘

    题目大意: 给定一个序列,每次查询一个区间\([l,r]\)中所有子序列分别去重后的和\(\bmod p\)(每次询问模数不同). 解题思路: 在太阳西斜的这个世界里,置身天上之森.等这场战争结束之后 ...

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

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

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

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

  5. P5072 [Ynoi2015]盼君勿忘

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

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

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

  7. Luogu P5072 [Ynoi2015]盼君勿忘

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

  8. [Ynoi2015]此时此刻的光辉(莫队)

    一道神题...自己写出来以后被卡常了...荣获洛谷最差解... 思路还是比较好想,对于每个数 \(\sqrt{n}\) 分块,对于 \(\sqrt{n}\) 以内的数,我们可以直接求出来.对于 \(\ ...

  9. Luogu5071 [Ynoi2015]此时此刻的光辉 【莫队】

    题目链接:洛谷 这个跟上上个Ynoi题目是一样的套路,首先我们知道\(n=\prod p_i^{\alpha_i}\)时\(d(n)=\prod (\alpha_i+1)\). 首先对所有数分解质因数 ...

随机推荐

  1. 1byte、1KB、4KB,1MB、1GB用16进制表示的范围。任意地址范围求字节数

    1byte.1KB.4KB,1MB.1GB用16进制表示的范围.任意地址范围求字节数 2018-02-12 18:27:48 望那伊人 阅读数 5032更多 分类专栏: 计算机相关   版权声明:本文 ...

  2. CentOS7 安装 Git

    环境: 系统版本:CentOS 7.5 Git 版本:2.20.1 一.安装 Git 1.下载编译工具 $ yum -y groupinstall "Development Tools&qu ...

  3. 采用二进制方式安装K8S集群,版本etcd-v3.3.10,flannel-v0.11.0,kubernetes-server-linux-amd64

    官方提供的几种Kubernetes部署方式 minikube Minikube是一个工具,可以在本地快速运行一个单点的Kubernetes,尝试Kubernetes或日常开发的用户使用.不能用于生产环 ...

  4. 天梯赛 L2-024. 部落

    题解:并查集,这里要用路径压缩来优化 代码:// 这里范围理错了, 浪费20分钟debug #include <set> #include <iostream> #includ ...

  5. springboot接收date类型参数

    springboot接收日期类型参数,实现自动转换. 1. 当请求类型为json,date类型字段为 json 字段时,可以使用如下两种方法 1.1. 当前参数加两个注解(有些文章说接收只需要加 @D ...

  6. 加快JavaScript加载和执行效率

    JavaScript 在浏览器中的性能成为开发者所面临的最重要的可用性问题.而这个问题又因 JavaScript 的阻塞特性变的复杂,也就是说当浏览器在执行 JavaScript 代码时,不能同时做其 ...

  7. Linux 知识

    linux下如何查看某软件是否已安装 因为linux安装软件的方式比较多,所以没有一个通用的办法能查到某些软件是否安装了.总结起来就是这样几类: 1.rpm包安装的,可以用rpm -qa看到,如果要查 ...

  8. SQL SERVER-修改服务器名称

    --query servername SELECT @@SERVERNAME --alter servername sp_dropserver 'oldname' go sp_addserver 'n ...

  9. 虚拟机更改MAC

    有两种方式修改MAC地址 方法一 现实中网卡一出厂就有MAC地址,虚拟机的MAC地址见下图,这个就相当于出厂MAC.在这里修改MAC相当于直接修改硬件MAC 方法二 这里修改MAC,硬件MAC并没有变 ...

  10. windows cmd命令学习

    tasklist|findstr "py"