LuoguP3396 - 哈希冲突

【LuoguP3396】哈希冲突
题目链接: https://www.luogu.org/problemnew/show/P3396

前言

话说快暑假了…但是好像没有几天假期啊。

然后期末考试之际做了找到题,发现暴力好像都能用分块优化。

分析

读完题目,发现想不到任何复杂度较低思路。对于几乎不接触分块的我,数据范围似乎没有什么用。

然后就打开了题解,才知道可以根号算法(不指分块),不过我统一把用sqrt函数的解法都叫做分块。

暴力的复杂度大概是$ O(mn) $ ,每次查询我们都需要$ O(n) $ 来遍历数组,修改是$ O(1) $。如果预处理的话那更玄学,每次查询时$ O(1) $,而修改是$ O(n^2) $ ,那么很有可能变成$ O(n^2m) $算法。

所以考虑只预处理$ \sqrt{n} $的模数,复杂度为$ O(n \sqrt{n}) $。

对于查询,如果查询的模数不超过$ \sqrt{n} $那么可以直接输出答案。如果模数超过$ \sqrt{n} $,我们只需要枚举模$ p $后的结果,把他们加起来,那么复杂度仍为$ \frac{n}{\sqrt{n}} = \sqrt{n} $。

对于修改,与预处理类似,还是只修改$ \sqrt{n} $的模数,由于只是单点修改,所以少了一层循环,那么复杂度为$ O(\sqrt{n}) $。

总复杂度最大是$ O((m + n)\sqrt{n}) $,然后就可以写代码了,代码极为简单,感觉像是暴力。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <stdio.h>
#include <math.h>
using namespace std;
int n, m, nb, v[150001], sum[1500][1500], tmpx, tmpy;
char cmd;
int main() {
cin >> n >> m, nb= sqrt(n);
for(int i= 1; i <= n; i++) cin >> v[i];
for(int i= 1; i <= nb; i++)
for(int j= 1; j <= n; j++) sum[i][j % i]+= v[j];
while(m--) {
cin >> cmd >> tmpx >> tmpy;
if(cmd == 'A') {
if(tmpx <= nb)
cout << sum[tmpx][tmpy] << endl;
else {
int ans= 0;
for(int i= tmpy; i <= n; i+= tmpx) ans+= v[i];
cout << ans << endl;
}
}
else {
for(int i= 1; i <= nb; i++) sum[i][tmpx % i]= sum[i][tmpx % i] - v[tmpx] + tmpy;
v[tmpx]= tmpy;
}
}
return 0;
}

后记

因为之前根号算法做比较少,而这道题给我很大的启示,以后一些只能想到暴力的题可以尝试使用根号来优化。

听说这题不用根号,而使用1/3次方作为块的大小效率更高。但是不会证明,而且复杂度比较玄学,可能只适用这一道题的数据吧。

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×