时空限制 1000ms / 128MB
题目描述
众所周知,模数的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。
输出格式:
对于每个询问输出一个正整数,进行回答。
说明
对于10%的数据,有n<=1000,m<=1000.
对于60%的数据,有n<=100000.m<=100000.
对于100%的数据,有n<=150000,m<=150000.
保证所有数据合法,且1<=value[i]<=1000.
题目分析
以前好像说过自己打死也不写分块的…嗯真香
容易想到朴素的暴力,令i从y开始迭代,每次加x,把沿路的val[i]都加上
可以发现当x(模数)很大的时候迭代次数就会很少
假如x为
n
\sqrt{n}
n级别,这样的迭代显然也是
O
(
n
)
O(\sqrt{n})
O(n)的
从中得到启发,可以预处理模数x不大于
n
\sqrt{n}
n的答案,这部分就可以
O
(
1
)
O(1)
O(1)回答
a
n
s
[
p
]
[
k
]
ans[p][k]
ans[p][k]表示mod p时k池内的总和
for(int i=1;i<=n;++i)
for(int j=1;j<=t;++j)
ans[j][i%j]+=a[i];
x大于
n
\sqrt{n}
n的部分直接暴力,复杂度也是
O
(
n
)
O(\sqrt{n})
O(n)
总复杂度
O
(
(
n
+
m
)
n
)
O((n+m)\sqrt{n})
O((n+m)n)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long lt;
int read()
{
int f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return f*x;
}
const int maxn=200010;
int n,m;
int a[maxn],ans[510][510];
char ss[5];
int main()
{
n=read();m=read();
for(int i=1;i<=n;++i) a[i]=read();
int t=sqrt(n);
for(int i=1;i<=n;++i)
for(int j=1;j<=t;++j)
ans[j][i%j]+=a[i];
while(m--)
{
scanf("%s",ss);
int x=read(),y=read();
if(ss[0]=='C'){
for(int i=1;i<=t;++i)
ans[i][x%i]+=y-a[x];
a[x]=y;
}
else if(ss[0]=='A'){
if(x<=t) printf("%d\n",ans[x][y]);
else{
int res=0;
if(y<x) for(int i=y;i<=n;i+=x) res+=a[i];
printf("%d\n",res);
}
}
}
return 0;
}