ZOJ Monthly, July 2015 K-hash 后缀数组去重做法
2015-07-27 12:05
363 查看
题意:意思有一个数字串,然后问子串构成的数字,有几个模k为0,1,2...k-1的。然后要求数字不能重复,也不能有前导零
做法:
先不考虑0的问题。
(1)首先o(32n)计算出所有的模k为0,1,2...k-1的子串有几个。此时不考虑重复。即每次计算出到第i位位置,每种串有多少个。然后把第i个位置插进去就能算了。
(2)然后利用后缀数组去重。如果height[i]=j那么表示第i个串与第i-1个串有j个子串相同,把这j个串的值从之前计算出来的答案中减去就好了。这个过程如果暴力的话是n^2,我开个sum数组是每次把前次的结果记录下来。这样如果height[i+1]比height[i]要大的话,比多出来的串的值加到sum数组里面去,然后ans减去sum即可。。。
考虑0
在(1)中不插入0做头位置,在(2)中不去首位置为0的重。即可。
PS:要预处理一个哈希数组,这样可以o(1)得到i到j这一段子串构成的数字的值。
PSS:关于这个做法的复杂度,我认为是o(32n)左右,但是我并不会证明,因为形式上看起来好像是o(n^2)。关键在于height数组的上下浮动是否是o(n)级别的。。。。这个代码在zoj上跑了120ms,比赛中提交的代码里是最快了。。。。
做法:
先不考虑0的问题。
(1)首先o(32n)计算出所有的模k为0,1,2...k-1的子串有几个。此时不考虑重复。即每次计算出到第i位位置,每种串有多少个。然后把第i个位置插进去就能算了。
(2)然后利用后缀数组去重。如果height[i]=j那么表示第i个串与第i-1个串有j个子串相同,把这j个串的值从之前计算出来的答案中减去就好了。这个过程如果暴力的话是n^2,我开个sum数组是每次把前次的结果记录下来。这样如果height[i+1]比height[i]要大的话,比多出来的串的值加到sum数组里面去,然后ans减去sum即可。。。
考虑0
在(1)中不插入0做头位置,在(2)中不去首位置为0的重。即可。
PS:要预处理一个哈希数组,这样可以o(1)得到i到j这一段子串构成的数字的值。
PSS:关于这个做法的复杂度,我认为是o(32n)左右,但是我并不会证明,因为形式上看起来好像是o(n^2)。关键在于height数组的上下浮动是否是o(n)级别的。。。。这个代码在zoj上跑了120ms,比赛中提交的代码里是最快了。。。。
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #define maxn 55555 using namespace std; int wa[maxn],wb[maxn],wv[maxn],wsa[maxn]; int ranks[maxn],height[maxn]; void calheight(int *r,int *sa,int n) { int i,j,k=0; for(i=1;i<=n;i++) ranks[sa[i]]=i; for(i=0;i<n ;height[ranks[i++]]=k) for(k?k--:0,j=sa[ranks[i]-1];r[i+k]==r[j+k];k++); return; } int cmp(int *r,int a,int b,int l) { return r[a]==r[b]&&r[a+l]==r[b+l]; } void build_sa(int *r,int *sa,int n,int m) { int i,j,p,*x=wa,*y=wb,*t; for(i=0;i<m;i++) wsa[i]=0; for(i=0;i<n;i++) wsa[x[i]=r[i]]++; for(i=1;i<m;i++) wsa[i]+=wsa[i-1]; for(i=n-1;i>=0;i--) sa[--wsa[x[i]]]=i; for(j=1,p=1;p<n;j*=2,m=p) { for(p=0,i=n-j;i<n;i++) y[p++]=i; for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j; for(i=0;i<n;i++) wv[i]=x[y[i]]; for(i=0;i<m;i++) wsa[i]=0; for(i=0;i<n;i++) wsa[wv[i]]++; for(i=1;i<m;i++) wsa[i]+=wsa[i-1]; for(i=n-1;i>=0;i--) sa[--wsa[wv[i]]]=y[i]; for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; } return; } int r[maxn],sa[maxn]; char str[55555]; int hash[55555],shi[55555]; int pan(char ch) { return ch-'0'; } int ans[111],k; void INIT() { int sum[100],add[111]; bool ling=false; memset(sum,0,sizeof(sum)); memset(add,0,sizeof(add)); memset(ans,0,sizeof(ans)); int len=strlen(str); for(int i=0;i<len;i++) { int dig=pan(str[i]); // dig%=k; for(int j=k-1;j>=0;j--) { add[(j*10+dig)%k]+=sum[j]; } if(dig!=0) add[dig%k]++; else ling=true; for(int j=0;j<=k;j++) { ans[j]+=add[j]; sum[j]=add[j]; add[j]=0; } } if(ling)ans[0]++; } int get_hash(int i,int j) { if(i==0)return hash[j-1]; int hi=hash[i-1]; int hj=hash[i+j-1]; hi=hi*shi[j]; hi%=k; int det=hj-hi; while(det<0)det+=k; return det; } int main(){ shi[0]=1; while(scanf("%s%d",str,&k)!=EOF){ int n=strlen(str); for(int i=1;i<=n;i++)shi[i]=shi[i-1]*10%k; for(int i=0;str[i];i++) r[i]=(int)str[i]; r =0; build_sa(r,sa,n+1,130); calheight(r,sa,n);//height(0-n) hash[0]=pan(str[0])%k; for(int i=1;i<n;i++) { hash[i]=hash[i-1]*10+pan(str[i]); hash[i]%=k; } INIT(); int last=0; int sum[33]; memset(sum,0,sizeof(sum)); int lf=-1; for(int i=2;i<=n;i++) { int first=sa[i]; if(height[i]>last) { for(int j=last+1;j<=height[i];j++) { int o=get_hash(first,j); sum[o]++; } } else { for(int j=last;j>height[i];j--) { int o=get_hash(lf,j); sum[o]--; } } last=height[i]; if(str[first]!='0') for(int j=0;j<k;j++) { ans[j]-=sum[j]; } lf=first; } int key=0; for(int i=0;i<k;i++) { printf("%d",ans[i]); if(i==k-1)printf("\n"); else printf(" "); } } }
相关文章推荐
- Github博客私人订制(二)
- DataTables warning: table id=dataTable - Requested unknown parameter 'acceptId' for row 0. For more
- Binary Tree Preorder Traversal
- POJ3468 A Simple Problem with Integers 【线段树+lazy】
- Nginx虚拟主机配置 + 虚拟主机支持PHP
- Github博客私人订制(一)
- 自己的面试过程
- <input type = "submit"> 提交方式和用js的form.submit()有什么区别?
- C# 委托事件
- GTK简单版计算器
- hdu5301and15年多校集训1002题(builds)(dfs)
- Oracle 10g ORA-12154: TNS: could not resolve the connect identifier specified 问题解决! 我同事遇到的问题。 用户名/
- 让spring mvc controller转换date类型
- 怒刷leetcode题目(3)226,83,142,86
- 排列与组合
- HTML 表
- Spring学习总结
- for语句的执行顺序
- Web实际应用中的编码问题
- IOS 应用图片解密工具