zoukankan      html  css  js  c++  java
  • 洛谷P3396 哈希冲突 (分块)

    洛谷P3396 哈希冲突

    题目背景

    此题约为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<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;
            }
        }
    }
    

    博主蒟蒻,随意转载.但必须附上原文链接

    http://www.cnblogs.com/real-l/

  • 相关阅读:
    C# String.Compare 方法测试
    C#checked 与 unchecked
    C#枚举类型
    C#结构体
    C越界和溢出的区别
    python/matlab : 将txt文件中的数据读为numpy数组
    matlab程序里调用python文件
    Python
    Pycharm调试及快捷键技巧
    Pycharm远程连接服务器debug时报错
  • 原文地址:https://www.cnblogs.com/real-l/p/9751572.html
Copyright © 2011-2022 走看看