博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
GDOI2013 哈希和
阅读量:5907 次
发布时间:2019-06-19

本文共 3864 字,大约阅读时间需要 12 分钟。

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
#include
#include
#include
#include
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\n",xzq); }}int main(){ Read(); Suffix(); Prepare(); Work();}

 

转载于:https://www.cnblogs.com/applejxt/p/3885398.html

你可能感兴趣的文章
matlab数字图像处理函数,MATLAB数字图像处理学习(二)|常用函数
查看>>
错误请联系管理员文件 index.php,帝国CMS订单、反馈信息、投稿与留言发邮件通知管理员的方法...
查看>>
小米笔记本装linux教程视频教程,Archlinux安装指南~小米笔记本Air 13.3英寸版本
查看>>
linux卸载nomachine,NoMachine 安装与配置及使用
查看>>
企业shell常见面试题及企业实战案例深入浅出讲解
查看>>
Load Test
查看>>
美文共赏
查看>>
RHEL6入门系列之十七,打包与压缩
查看>>
SQLite 3.7.13的加密解密(二)—— 开放宏定义
查看>>
禁止server 2008域端口的脚本
查看>>
数据结构图之二(最小生成树--普里姆算法)
查看>>
HTML输出 一 控制列背景颜色
查看>>
Redis for Windows(C#缓存)配置文件详解
查看>>
回忆2013年的点点滴滴(各个方面)
查看>>
ASP.NET MVC 4使用PagedList.Mvc分页
查看>>
HDOJ 2066 floyed优化算法
查看>>
window.onscroll
查看>>
开发常用动画收集
查看>>
nginx js、css多个请求合并为一个请求(concat模块)
查看>>
mybatis实战教程(mybatis in action)之五:与spring3集成
查看>>