洛谷P3396 哈希冲突
题目背景
此题约为NOIP提高组Day2T2难度。
题目描述
众所周知,模数的hash会产生冲突。例如,如果模的数p=7
,那么4
和11
便冲突了。
B君对hash冲突很感兴趣。他会给出一个正整数序列value[]
。
自然,B君会把这些数据存进hash池。第value[k]
会被存进(k%p)
这个池。这样就能造成很多冲突。
B君会给定许多个p
和x
,询问在模p
时,x
这个池内数的总和
。
另外,B君会随时更改value[k]
。每次更改立即生效。
保证1<=p<n1<=p<n.
输入输出格式
输入格式:
第一行,两个正整数n,m
,其中n
代表序列长度,m
代表B君的操作次数。
第一行,n
个正整数,代表初始序列。
接下来m
行,首先是一个字符cmd
,然后是两个整数x,y
。
-
若
cmd='A'
,则询问在模x
时,y
池内数的总和。 -
若
cmd='C'
,则将value[x]
修改为y
。
输出格式:
对于每个询问输出一个正整数,进行回答。
输入输出样例
输入样例#1:
10 5
1 2 3 4 5 6 7 8 9 10
A 2 1
C 1 20
A 3 1
C 5 1
A 5 0
输出样例#1:
25
41
11
说明
样例解释
A 2 1
的答案是1+3+5+7+9=25
.
A 3 1
的答案是20+4+7+10=41
.
A 5 0
的答案是1+10=11
.
数据规模
对于10%
的数据,有n<=1000,m<=1000
.
对于60%
的数据,有n<=100000.m<=100000
.
对于100%
的数据,有n<=150000,m<=150000
.
保证所有数据合法,且1<=value[i]<=1000
.
Solution
首先,思考暴力,对于询问,如下
for(int i=x;i<=n;i+=p) {
ans+=v[i];
}
然后由于数据水,暴力程序交上去91分?
#include<bits/stdc++.h>
#define rg register
#define il inline
#define Min(a,b) (a)<(b)?(a):(b)
#define Max(a,b) (a)>(b)?(a):(b)
#define lol long long
#define in(i) (i=read())
using namespace std;
int read() {
int ans=0,f=1; char i=getchar();
while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+i-'0',i=getchar();
return ans*=f;
}
int n,m,v[2000010];
int main()
{
in(n),in(m);
for(rg int i=1;i<=n;i++) in(v[i]);
for(rg int i=1;i<=m;i++){
char op[5]; int x,y;
scanf("%s",op); in(x),in(y);
if(op[0]=='A') {
int ans=0;
for(int p=y;p<=n;p+=x) ans+=v[p];
cout<<ans<<endl;
}else v[x]=y;
}
}
再换种思路,假设对于一个数,我们怎么处理出它对答案的贡献呢?
我们可以开一个桶,只不过是二维的,(sum[p][q])表示模数为(p),余数为(q(q=i mod p))的桶,这样
for(int i=1;i<=n;i++) {
for(int p=1;p<=n;i++)
sum[p][i%p]+=v[i];
}
这个预处理是(O(n^2))的,查询虽然(O(1)),但是好像没什么用
其实是有的
我们可以分块
...
其实也是暴力....
分块本来就是稍微优雅那么一点的暴力
如果模数p>(sqrt n),那么对于对于答案有贡献的是(lfloorfrac{n}{p}
floor<sqrt n),所以我们不如暴力统计
否则,(O(1))查询即可
修改?也是只暴力更新(p<sqrt n)的桶
Code
#include<bits/stdc++.h>
#define lol long long
#define in(i) (i=read())
using namespace std;
const int N=2e6;
int read() {
int ans=0,f=1; char i=getchar();
while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+(i^48),i=getchar();
return ans*f;
}
int n,m,a[N],sum[1010][1010];
int main()
{
in(n),in(m); int blo=pow(n,0.33);
for(int i=1;i<=n;i++) in(a[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=blo;j++)
sum[j][i%j]+=a[i];
while(m--) {
char op[10];int x,y;
scanf("%s",op);in(x),in(y);
if(op[0]=='A') {
if(x<=blo) printf("%d
",sum[x][y]);
else {
int ans=0;
for(int i=y;i<=n;i+=x) ans+=a[i];
printf("%d
",ans);
}
}
else {
for(int i=1;i<=blo;i++)
sum[i][x%i]=sum[i][x%i]-a[x]+y;
a[x]=y;
}
}
}