• GDOI2013 哈希和


    Description

    对于一个由小写字母组成的字符串s,我们定义:



    1、s[i]表示字符串s的第i个字符,其中有1<=i<=len(s)



    2、g(s[i])表示字符s[i]的ASCII码与字符‘a’的ASCII码的差值。



    3、substr(i,j)表示由字符串s的第i个字母至第j个字母组成的一个连续子串,其中有1<=i<=j<=len(s)。



    4、hash(i,j)表示substr(i,j)的哈希值,其中hash(i,j) =

    现在给出一个由小写字母组成的字符串s,以及m个询问,每个询问给出两个整数x,y(x<=y),表示询问s的所有不同的连续子串中,字典序排名为x到y之间的所有字符串的哈希值的总和(包括x和y)。
     

    Input

    第一行一个由小写字母组成的字符串s,字符串的长度不会超过10^5.假设字符串s的不同连续子串的数目为t。



    第二行有一个整数m(1<=m<=10^5),表示有m个询问。



    接下来一共有m行,每行两个整数xi,yi(1<=xi<=yi<=t),意义如题所述。

    Output

    对于每一组询问,输出一个整数,表示哈希和,由于数值可能很大,所以你只要输出答案模12580即可。
     

    Sample Input

    abcab



    5



    1 1



    1 5



    2 5



    4 11



    1 12

    Sample Output

    0



    7106



    7106



    1657



    3039
     

    Data Constraint

    对于20%的数据,n<=100,m<=100



    对于40%的数据,n<=5000,m<=10^5



    对于100%的数据,n<=10^5,m<=10^5
     

    Hint

    字符串abcab一共有12个不同的连续子串,这些子串按照字典序从小到大排列分别为a,ab,abc,abca,abcab,b,bc,bca,bcab,c,ca,cab。

    先用SA求不同字串的个数。再预处理以第一位开头,第i位结尾的所有字串的哈希和,即前缀和

    对于输入的x,y,先二分出它们在哪个后缀上,然后用类似前缀和相减的处理即可.

    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    
    using namespace std;
    typedef long long ll;
    
    int n,mn,x,i;
    int co[100011],sa[100011],rank[100011],h[100011],nr[100011],sum[100011];
    int a[100011],b[100011],ts[100011],hash[100011],suf[100011];
    ll son[100011];
    char s[100011];
    char c;
    
    void Read()
    {
        while(c=getchar(),c<'a'||c>'z');
        s[++n]=c;
        while(c=getchar(),c>='a'&&c<='z')s[++n]=c;
    }
    
    void sort(int *a)
    {
        int i;
        for(i=0;i<=mn;i++)co[i]=0;
        for(i=1;i<=n;i++)co[a[i]+1]++;
        for(i=1;i<=mn;i++)co[i]+=co[i-1];
        for(i=1;i<=n;i++)nr[i]=0;
        for(i=1;i<=n;i++){
            co[a[sa[i]]]++;
            nr[co[a[sa[i]]]]=sa[i];
        }
        for(i=1;i<=n;i++)sa[i]=nr[i];
    }
    
    void getrank()
    {
        int i;
        x=0;
        for(i=1;i<=n;i++){
            if(i==1||a[sa[i]]!=a[sa[i-1]]||b[sa[i]]!=b[sa[i-1]])x++;
            rank[sa[i]]=x;
        }
    }
    
    void Suffix()
    {
        int i,j,k,l,last;
        if(27>n)mn=27;
        else mn=n;
        for(i=1;i<=n;i++){
            a[i]=s[i]-96;
            b[i]=0;
            sa[i]=i;
        }
        sort(a);
        getrank();
        l=1;
        while(x!=n){
            for(i=1;i<=n;i++){
                a[i]=rank[i];
                if(i+l<=n)b[i]=rank[i+l];
                else b[i]=0;
            }
            sort(b);
            sort(a);
            getrank();
            l*=2;
        }
        last=0;
        for(i=1;i<=n;i++){
            if(last)last--;
            if(rank[i]==1)continue;
            j=i;
            k=sa[rank[i]-1];
            while(j+last<=n&&k+last<=n&&s[j+last]==s[k+last])last++;
            h[rank[i]]=last;
        }
    }
    
    int ha(int st,int len)
    {
        int z,ed;
        ed=st+len-1;
        z=((sum[ed]-sum[st-1])%12580+12580)%12580;
        z=((z-hash[st-1]*ts[len])%12580+12580)%12580;
        return z;
    }
    
    void Prepare()
    {
        int j;
        j=1;
        for(i=1;i<=n;i++){
            son[i]=(ll)son[i-1]+n-sa[i]+1-h[i];
            hash[i]=(hash[i-1]*26+s[i]-97)%12580;
            sum[i]=(sum[i-1]+hash[i])%12580;
            j=(j*26)%12580;
            ts[i]=(ts[i-1]+j)%12580;
        }
        for(i=1;i<=n;i++){
            suf[i]=((suf[i-1]+ha(sa[i],n-sa[i]+1)-ha(sa[i],h[i]))%12580+12580)%12580;
        }
    }
    
    int find(ll x)
    {
        int l,r,mid;
        l=1;
        r=n;
        while(l<=r){
            mid=(l+r)/2;
            if(son[mid]>=x)r=mid-1;
            else l=mid+1;
        }
        return l;
    }
    
    int Work()
    {
        int i,m,q,xzq,j,xs,zs;
        ll xl,zl;
        scanf("%d",&m);
        for(i=1;i<=m;i++){
            xl=0;
            zl=0;
            scanf("%lld%lld",&xl,&zl);
            xs=find(xl);
            zs=find(zl);
            if(zs-1>xs)xzq=((suf[zs-1]-suf[xs])%12580+12580)%12580;
            else xzq=0;
            xl=xl-son[xs-1];
            zl=zl-son[zs-1];
            if(xs!=zs){
                xzq=((xzq+ha(sa[xs],n-sa[xs]+1)-ha(sa[xs],h[xs]+xl-1))%12580+12580)%12580;
                xzq=((xzq+ha(sa[zs],h[zs]+zl)-ha(sa[zs],h[zs]))%12580+12580)%12580;
            }
            else{
                xzq=((xzq+ha(sa[xs],h[xs]+zl)-ha(sa[xs],h[xs]+xl-1))%12580+12580)%12580;
            }
            printf("%d
    ",xzq);
        }
    }
    
    int main()
    {
        Read();
        Suffix();
        Prepare();
        Work();
    }
  • 相关阅读:
    IIS 6.0下安装SSL数字证书实现https访问
    使用SQL2005自带扩展函数对字符串进行MD5加密(转)
    Posix多线程编程学习笔记(三)—信号灯(1)--转自湖光倒影
    利用pthread_mutex对多进程上锁
    ObjectiveC中的锁
    Linux内存管理之mmap详解
    cocoa应用程序生命周期
    多线程编程互斥锁
    [New Book]Flex第一步 国内第一本关于Flex的书籍
    ASP.NET中实现二级或多级域名(修改UrlRewrite)
  • 原文地址:https://www.cnblogs.com/applejxt/p/3885398.html
Copyright © 2020-2023  润新知