[GDOI2013][JZOJ3277]哈希和
来源:互联网 发布:sql unique啥意思 编辑:程序博客网 时间:2024/05/24 02:28
题目大意
设字符串
其中
给定字符串
题目分析
本题的难点在于如何求出哈希值的和,其它的我们直接离线,将询问差分,然后存在一个桶里面,排个序,求答案时我们直接按照排序后的顺序扫一遍,将可处理的询问处理了。
那么哈希值之和怎么求呢?
我们定义如下数组
因为前缀和相减之后,剩下的值就是原串最左端到区间内所有位置组成的的子串的哈希和,显然和这个区间最左端开始的子串多出同样的字符串,都是原串最左端到区间最左端的左端组成的子串,那么我们将他乘上差的几位幂数和,减掉就行了。
具体细节请读者自行思考,详见代码实现。
代码实现
#include <algorithm>#include <iostream>#include <cstring>#include <cstdio>using namespace std;typedef long long LL;const int N=100050;const int M=100050;const int P=12580;const int D=26;struct Q{ LL K; int id;}qu[N<<1];bool operator<(Q a,Q b){ return a.K<b.K;}int Ws[N],Wv[N],x[N],y[N],SA[N],rank[N],height[N],sum[N],p[N],hash[N],ans[M][3];bool deal[M];LL q[M][2];char s[N];int n,m;void pre(){ p[0]=D; for (int i=1,j=D*D%P;i<=n;i++,(j*=D)%=P) p[i]=(p[i-1]+j)%P; hash[0]=s[0]-'a'; for (int i=1;i<n;i++) hash[i]=((LL)hash[i-1]*D%P+(s[i]-'a'))%P; sum[0]=hash[0]; for (int i=1;i<n;i++) sum[i]=(sum[i-1]+hash[i])%P;}bool cmp(int *r,int i,int j,int l){ return r[i]==r[j]&&r[i+l]==r[j+l];}void DA(){ int mx=0,l=1,p=0,i; for (i=0;i<n;i++)mx=max(mx,Wv[i]=x[i]=s[i]-'a'); for (i=0;i<=mx;i++)Ws[i]=0; for (i=0;i<n;i++)Ws[Wv[i]]++; for (i=1;i<=mx;i++)Ws[i]+=Ws[i-1]; for (i=n-1;i>=0;i--)SA[--Ws[Wv[i]]]=i; for (;l<=n&&p!=n;l<<=1) { for (p=0,i=n-l;i<n;i++)y[p++]=i; for (i=0;i<n;i++)if(SA[i]>=l)y[p++]=SA[i]-l; for (mx=0,i=0;i<n;i++)mx=max(mx,Wv[i]=x[y[i]]); for (i=0;i<=mx;i++)Ws[i]=0; for (i=0;i<n;i++)Ws[Wv[i]]++; for (i=1;i<=mx;i++)Ws[i]+=Ws[i-1]; for (i=n-1;i>=0;i--)SA[--Ws[Wv[i]]]=y[i]; for (i=0;i<n;i++)y[i]=x[i],x[i]=0; for (p=0,x[SA[0]]=0,i=1;i<n;i++)x[SA[i]]=cmp(y,SA[i-1],SA[i],l)?p:++p; } for (i=0;i<n;i++)rank[SA[i]]=i;}void get_height(){ for (int k=0,i=0;i<n;i++) { k?k--:k; if (!rank[i]) continue; int j=SA[rank[i]-1]; while (i+k<n&&j+k<n&&s[i+k]==s[j+k]) k++; height[rank[i]]=k; }}int hashsum(int st,int en){ if (st>en) return 0; return (((LL)sum[en]-(st?sum[st-1]:0)-(LL)(st?hash[st-1]:0)*p[en-st]%P)%P+P)%P;}int prefixsum(int st,int en1,int en2){ return ((hashsum(st,en2)-hashsum(st,en1-1))%P+P)%P;}void calc(){ int ptr=1,cnt=0; LL kth=0,las=0; for (int i=0;i<n;i++) { las=kth; kth+=n-SA[i]-height[i]; while (ptr<=m<<1&&qu[ptr].K<=kth) { int j=qu[ptr].id,l=deal[j]?2:1; deal[j]=1; if (!qu[ptr].K) ans[j][l]=0; else ans[j][l]=(cnt+prefixsum(SA[i],SA[i]+height[i],SA[i]+height[i]+qu[ptr].K-las-1))%P; ptr++; } cnt=(cnt+prefixsum(SA[i],SA[i]+height[i],n-1))%P; } for (int i=1;i<=m;i++) ans[i][0]=((ans[i][2]-ans[i][1])%P+P)%P;}int main(){ freopen("hashsum.in","r",stdin); freopen("hashsum.out","w",stdout); scanf("%s",s); n=strlen(s); scanf("%d",&m); for (int i=1;i<=m;i++) { scanf("%lld%lld",&q[i][0],&q[i][1]); qu[(i<<1)-1].K=q[i][0]-1,qu[i<<1].K=q[i][1]; qu[(i<<1)-1].id=i,qu[i<<1].id=i; } sort(qu+1,qu+1+(m<<1)); pre(); DA(); get_height(); calc(); for (int i=1;i<=m;i++) printf("%d\n",ans[i][0]); fclose(stdin); fclose(stdout); return 0;}
0 0
- [GDOI2013][JZOJ3277]哈希和
- 【jzoj3277】【GDOI2013】【哈希和】【后缀数组】
- 【GDOI2013模拟7】最大异或和
- GDOI2013 整数分拆
- 【GDOI2013模拟1】屏保
- 【DP】GDOI2013 整数分拆
- 【GDOI2013模拟4】贴瓷砖
- 【GDOI2013模拟4】贴瓷砖
- 【jzoj3282】【GDOI2013】【飞行棋】【期望】【高斯消元】
- 【分块or转化枚举】GDOI2013 大山王国的科举考试
- [jzoj]3172. 【GDOI2013模拟4】贴瓷砖(AC自动机+卡时卡空)
- 哈希表和哈希算法
- 哈希表和完美哈希
- 哈希表和完美哈希
- 哈希表和完美哈希
- 哈希表和完美哈希
- 分布式哈希和一致性哈希
- 分布式哈希和一致性哈希
- Android_低功耗
- 多屏复杂动画CSS技巧三则
- Git 使用笔记
- hdu3966Aragorn's Story【树链剖分+树状数组】
- hdu1272 小希的迷宫(并查集)
- [GDOI2013][JZOJ3277]哈希和
- httpclient 上传文件、下载文件
- JAVA中List、Map、Set的区别与选用
- solr创建多表关联索引时子表的索引创建失败
- document.getElementByID('btn').click();
- manifest.xml 中元素含义
- 写在2015农历年的最后以及2016农历年的开始
- HP监控软件sitescope的简介和应用
- 自己写的一套布局适应,以dp来命名