哈希冲突(分块)

哈希冲突(luogu)

题目背景

此题约为NOIP提高组Day2T2难度。

题目描述

众所周知,模数的hash会产生冲突。例如,如果模的数p=7,那么411便冲突了。

B君对hash冲突很感兴趣。他会给出一个正整数序列value[]

自然,B君会把这些数据存进hash池。第value[k]会被存进(k%p)这个池。这样就能造成很多冲突。

B君会给定许多个px,询问在模p时,x这个池内**数的总和**。

另外,B君会随时更改value[k]。每次更改立即生效。

保证1<=p1<=p<n.

输入格式

第一行,两个正整数n,m,其中n代表序列长度,m代表B君的操作次数。

第一行,n个正整数,代表初始序列。

接下来m行,首先是一个字符cmd,然后是两个整数x,y

  • cmd='A',则询问在模x时,y池内数的总和。

  • cmd='C',则将value[x]修改为y

输出格式

对于每个询问输出一个正整数,进行回答。

Solution

神奇的解法:根号算法——不只是分块

设ans[x][y]表示膜x余y的答案(先别急着说数据范围太大)

我们发现数组记忆的方法预处理复杂度为O(n^2),操作复杂度为O(n);

而暴力法无预处理,操作复杂度为O(n^2);

考虑到数组大小的问题,我们要改进数组记忆法

发现x越大时询问操作复杂度越低,当x>根号n时复杂度<根号n

于是有了新的结合版算法:预处理x<=根号n的ans数组,询问时x<=根号n,x>根号n暴力

整个复杂度O((n+m)* 根号n);

Code

#include 
#include 
#include 
using namespace std;
const int N=15e4+10;
int ans[1000][1000],n,m,d[N],x,y,p;
char s[5];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&d[i]);
    p=sqrt(n);
    for(int i=1;i<=p;i++)
        for(int j=1;j<=n;j++)
            ans[i][j%i]+=d[j];
    while(m--)
    {
        scanf("%s%d%d",s,&x,&y);
        if(s[0]=='A')
        {
            if(x<=p)
            {
                printf("%d\n",ans[x][y]);
                continue;
            }
            int an=0;
            for(int i=y;i<=n;i+=x)
                an+=d[i];
            printf("%d\n",an);
        }
        else
        {
            for(int i=1;i<=p;i++)
                ans[i][x%i]+=y-d[x];
            d[x]=y;
        }
    }
    return 0;
}

 

你可能感兴趣的:(哈希冲突(分块))