【洛谷 P3396 哈希冲突】解题报告(根号分治)
时间:2021-07-12
本文章向大家介绍【洛谷 P3396 哈希冲突】解题报告(根号分治),主要包括【洛谷 P3396 哈希冲突】解题报告(根号分治)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
简要题意
已知一个长度为 \(n\) 的数列 \(a\),共 \(m\) 次操作:
- 操作
A
:询问 \(\sum\limits_{i\bmod x=y}a_i\)。 - 操作
C
:\(a_x\gets y\)。
数据范围:\(1\le n,m\le 1.5\times 10^5\),\(1\le a_i\le 10^3\)。
方法一
考虑暴力,询问等价于如下代码:
for(int i=y;i<=n;i+=x) now += a[i];
修改等价于如下代码:
a[x] = y;
时间复杂度:
预处理 | 每次询问 | 总复杂度 |
---|---|---|
\(O(1)\) | \(O(n)\) | \(O(n^2)\) |
方法二
考虑预处理 \(ans_{p,k}=\sum\limits_{i\bmod p=k}a_i\),然后询问等价于如下代码:
now = ans[x][y];
修改等价于如下代码:
for(int p=1;p<=n;p++) ans[p][x%p] -= a[i];
a[i] = y;
for(int p=1;p<=n;p++) ans[p][x%p] += a[i];
时间复杂度:
预处理 | 每次询问 | 总复杂度 |
---|---|---|
\(O(n^2)\) | \(O(1)\) | \(O(n^2)\) |
方法三(正解)
考虑将上面两种方法的优点结合起来。
第一种方法每次询问的复杂度其实是 \(O(\frac{n}{x})\),当 \(n\) 确定时是一个关于 \(x\) 的反比例函数,显然当 \(x\ge\sqrt{n}\) 时,单次询问复杂度为 \(O(\sqrt{n})\)。
第二种方法瓶颈在预处理,每处理一个模数 \(x\) 的复杂度是 \(O(n)\),将 \(x\in[1,\sqrt{n}]\) 的结果处理出来的复杂度为 \(O(n\sqrt{n})\),单次询问复杂度为 \(O(1)\)。
可以发现第一种方法可以处理 \(x\ge\sqrt{n}\),第二种方法可以处理 \(x\le\sqrt{n}\),他们结合起来就可以得到所有询问的结果。
对于修改操作,我们枚举 \(x\in[1,\sqrt{n}]\) 通过同【方法二】的方法修改即可。
时间复杂度:
预处理 | 每次询问 | 总复杂度 |
---|---|---|
\(O(n\sqrt{n})\) | \(O(\sqrt{n})\) | \(O(n\sqrt{n})\) |
参考代码
//By: Luogu@rui_er(122461)
#include <bits/stdc++.h>
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x--)
#define debug printf("Running %s on line %d...\n",__FUNCTION__,__LINE__)
using namespace std;
typedef long long ll;
const int N = 1.5e5+5, K = 388;
int n, m, a[N], ans[K][K];
template<typename T> void chkmin(T &x, T y) {if(x > y) x = y;}
template<typename T> void chkmax(T &x, T y) {if(x < y) x = y;}
int main() {
scanf("%d%d", &n, &m);
rep(i, 1, n) scanf("%d", &a[i]);
rep(p, 1, K-1) rep(i, 1, n) ans[p][i%p] += a[i];
while(m--) {
char op[2];
int x, y;
scanf("%s%d%d", op, &x, &y);
if(op[0] == 'A') {
if(x < K) printf("%d\n", ans[x][y]);
else {
int now = 0;
for(int i=y;i<=n;i+=x) now += a[i];
printf("%d\n", now);
}
}
else {
rep(p, 1, K-1) ans[p][x%p] -= a[x];
a[x] = y;
rep(p, 1, K-1) ans[p][x%p] += a[x];
}
}
return 0;
}
博文作者:rui_er。本博客所有公开(无密码)博文可根据 CC BY-NC-SA 4.0 协议进行转载,非公开博文可与作者联系获得许可后转载。
原文地址:https://www.cnblogs.com/ruierqwq/p/LG-P3396.html
- RSA 2018:从大会议题看2018年网络安全趋势
- Silverlight:Mouse Avoiding 躲避鼠标效果
- CTreeCtrl 控件使用总结
- 在ASP.NET MVC 4中使用Kendo UI Grid
- 每周四更面试题:True+True=?
- iis7 发布mvc 遇到的HTTP错误 403.14-Forbidden Web 服务器被配置为不列出此目录的内容
- NET中验证控件表达式汇总
- 动态执行超过4000个字符的SQL
- 在ASPNET中使用JS集锦
- 小程序又又又……
- js中页面刷新和页面跳转的方法总结
- PixelBender(着色器)初体验
- Centos下堡垒机Jumpserver V3.0环境部署完整记录(1)-安装篇
- CSS好看的按钮
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Flutter “孔雀开屏”动画效果
- Flutter 使用Navigator进行局部跳转页面
- Flutter 动画鼻祖之CustomPaint
- 【Flutter实战】Flutter 中那么多组件,难道要都学一遍?
- 【Flutter组件终结篇】332个组件 658页PDF
- Kubernetes在pod中配置hosts解析域名
- 【Flutter 实战】简约而不简单的计算器
- Flutter 中渐变的高级用法
- 【Flutter实战】动画核心(1/2)
- 【Flutter实战】动画核心(2/2)
- Flutter 1.17 新 Material motion 规范的预构建动画
- Canonical通过Flutter启用Linux桌面应用程序支持
- Flutter 快捷开发 Mac Android Studio 篇
- TRTC Android端开发接入学习之互动直播(七)
- Flutter 实现酷炫的3D效果