洛谷P3396 哈希冲突【分块】

时空限制 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值