P3396 哈希冲突

P3396 哈希冲突(根号分治)

像这样的题大多可以考虑根号分治,也就是和模数有关的。

我们对于询问的值来分治:

对于小于 (sqrt{n}) 的模数:

说明剩余系也不超过 (sqrt{n}) 个,于是我们可以预处理这样的询问,需要时直接回答即可。

预处理时间复杂度是 (O(nsqrt{n})) 的,询问 (O(1))

对于大于等于 (sqrt{n}) 的模数:

每个剩余系里面的元素不超过 (sqrt{n}) 个。

于是对于每一个询问,我们可以直接枚举起点,然后不断地累加这个剩余系里面下标的答案即可。

这部分询问是 (O(sqrt{n})) 的,时间复杂度是 (O(msqrt{n}))

代码:

#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
	x=0;bool f=false;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	x=f?-x:x;
	return ;
}
template <typename T>
inline void write(T x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10^48);
	return ;
}
const int N=1e5+5e4+5,M=405,INF=1e9+7;
int n,m,t,a[N];
int sum[M][M];//摸i时第j个池子的情况 
int main(){
	read(n),read(m);t=sqrt(n);
	for(int i=1;i<=n;i++) read(a[i]);
	for(int i=1;i<=t;i++) for(int j=1;j<=n;j++) sum[i][j%i]+=a[j];
	for(int i=1,x,y;i<=m;i++){
		char op[5];
		scanf("%s",op);read(x),read(y);
		if(op[0]=='A'){
			if(x<=t) write(sum[x][y]),putchar('
');
			else{
				int Sum=0;
				for(int j=y;j<=n;j+=x) Sum+=a[j];
				write(Sum),putchar('
');
			}
		}
		else{
			for(int j=1;j<=t;j++) sum[j][x%j]-=a[x];
			for(int j=1;j<=t;j++) sum[j][x%j]+=y;
			a[x]=y;
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Akmaey/p/14667469.html