1. 程式人生 > >哈希沖突[分塊(思想)]

哈希沖突[分塊(思想)]

長度 pri Go getchar 更改 數據規模 size pos har

題目背景

此題約為NOIP提高組Day2T2難度。

題目描述

眾所周知,模數的hash會產生沖突。例如,如果模的數p=7,那麽411便沖突了。

B君對hash沖突很感興趣。他會給出一個正整數序列value[]

自然,B君會把這些數據存進hash池。第value[k]會被存進(k%p)這個池。這樣就能造成很多沖突。

B君會給定許多個px,詢問在模p時,x這個池內數的總和

另外,B君會隨時更改value[k]。每次更改立即生效。

保證1<=p<n1<=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.

題解

做法分析:

  (sqrt(),不只是分塊)

  (1)首先,我們先處理出sqrt()內的模數池的值,這樣詢問就只要o(1),預處理o(n√n)。

  (2)其次,當模數大於sqrt()時,我們暴力一次的代價為o(√n)

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
int ans[400][150001],ch[150001],n,m,tmp;
int read()
{
    int x=0,w=1;char ch=getchar();
    while(ch>9||ch<0){if(ch==-)w=-1;ch=getchar();}
    while(ch>=0&&ch<=9)x=x*10+ch-0,ch=getchar();
    return x*w;
}

void build()
{
    for(int i=1;i<=n;i++)
        for(int j=1;j<=tmp;j++)
        ans[j][i%j]+=ch[i];
}

void change(int x,int v)
{
    for(int i=1;i<=tmp;i++)
    ans[i][x%i]=ans[i][x%i]-ch[x]+v;
    ch[x]=v;
}

int query(int x,int v)
{
    int ans=0;
    for(int i=v;i<=n;i+=x)
    {
        ans+=ch[i];
    }
    return ans;
}

int main()
{
    n=read();m=read();
    tmp=sqrt(n);
    for(int i=1;i<=n;i++)ch[i]=read();
    build();
    for(int i=1;i<=m;i++)
    {
        char qwq;cin>>qwq;int x=read();int y=read();
        if(qwq==A){if(x<=tmp)printf("%d\n",ans[x][y]);
        else printf("%d\n",query(x,y));}
        if(qwq==C)change(x,y);
    }
    return 0;
}

哈希沖突[分塊(思想)]