洛谷P3396 :哈希冲突(根号算法,分块)

题目描述
众所周知,模数的hash会产生冲突。例如,如果模的数p=7,那么4和11便冲突了。
B君对hash冲突很感兴趣。他会给出一个正整数序列value[]。
自然,B君会把这些数据存进hash池。第value[k]会被存进(k%p)这个池。这样就能造成很多冲突。
B君会给定许多个p和x,询问在模p时,x这个池内数的总和。
另外,B君会随时更改value[k]。每次更改立即生效。
保证
1 <= p < n , 1 <= p < n
1 <= p < n.

数据规模
对于10%的数据,有n<=1000,m<=1000.
对于60%的数据,有n<=100000.m<=100000.
对于100%的数据,有n<=150000,m<=150000.
保证所有数据合法,且1<=value[i]<=1000.

解法:每次询问的答案为:
for(int i = y; i <= n; i += x) ans += value[i]
观察到当x较大时,复杂度较低,x较小时复杂度较高
考虑预处理答案:ans[p][k] 表示 所有位置% p 余 k 的位置的数的和。枚举复杂度为o(n ^ 2)
在这里插入图片描述
考虑block 取 sqrt(n) 时,可以用n * sqrt(n)的时间预处理出 x <= sqrt(n)的所有可能答案。
对于x <= block的询问,直接o(1) 输出预处理的答案。
对于x > block的询问,因为此时x > sqrt(n),可以在sqrt(n)时间内得到答案。
考虑更新,修改一个值后,暴力枚举 p, 更新ans[p][x % p]的值,复杂度也为sqrt(n)。
总复杂度为o((n + m) * sqrt(n));

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
const int mx = 2e3 + 10;
int num,block,n,m,q,l[1100],r[1100],belong[maxn];
int a[maxn],ans[maxn][1100];
char op[10];
int main() {
	scanf("%d%d",&n,&m);
	for(int i = 1; i <= n; i++) {
		scanf("%d",&a[i]);
	}
	block = sqrt(n);
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= block; j++)
			ans[j][i % j] += a[i];
	for(int i = 1; i <= m; i++) {
		scanf("%s",op);
		int x,y;
		scanf("%d%d",&x,&y);
		if(op[0] == 'A') {
			int res = 0;
			if(x > block) {
				for(int i = y; i <= n; i += x) {
					res += a[i]; 
				}
				printf("%d\n",res);
			}
			else {
				printf("%d\n",ans[x][y]);
			}
		}
		else {
			for(int i = 1; i <= block; i++) {
				ans[i][x % i] -= a[x]; 
			}
			for(int i = 1; i <= block; i++) {
				ans[i][x % i] += y;
			}
			a[x] = y;
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值