HDU 5008 (2014西安网络赛第二题)后缀数组
来源:互联网 发布:js判断时间戳大小 编辑:程序博客网 时间:2024/04/30 06:26
先把整个字符串的字串个数求出(详情请看罗穗蹇论文),s[i]=s[i-1]+n-sa[i]-height[i].因为对每个以i开头的前缀个数为这么多(减去了与前面重复的子串)。
求出来之后二分,注意每个字串是字符串的前缀,况且sa数组是有序的,如果这些有序的后缀所组成的子串都不够k的话,就继续找,这是一个二分的过程,然后假设剩下的个数为p,则可以从这个串的头一直到p+height[i],然后就是找开头l,从这个点开始往后找,找height大于等于这个长度的串,取左端最小值即可。
下面是AC代码:
#include<cstdio>#include<cstring>#include<vector>#include<algorithm>#define LL int#define inf 31#define mod 1000003#define maxn 200100using namespace std;int r[maxn];int Rank[maxn],sa[maxn],height[maxn];int wa[maxn],wb[maxn],wv[maxn],ws[maxn];char a[maxn],b[maxn];int cmp(int *r,int a,int b,int le){ return r[a]==r[b]&&r[a+le]==r[b+le];}void da(int *r,int *sa,int n,int m){ int i,j,p,*x=wa,*y=wb,*t; for ( i = 0; i < m; i++) ws[i]=0; for ( i = 0; i < n; i++) ws[ x[i] = r[i] ]++; for ( i = 1; i < m; i++) ws[i]+=ws[i-1]; for ( i = n-1; i >= 0; i--) sa[--ws[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++) ws[i]=0; for ( i = 0; i < n; i++) ws[wv[i]]++; for ( i = 1; i < m; i++) ws[i]+=ws[i-1]; for ( i = n-1; i >= 0 ; i--) sa[--ws[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 ;}void calheight( int *r,int *sa,int n){ int i,j,k=0; for ( i = 0; i <=n ; i++) Rank[sa[i]]=i; for(i=0;i<n;height[Rank[i++]]=k) for(k?k--:0,j=sa[Rank[i]-1];r[i+k]==r[j+k];k++); return ;}struct pi{ int min; int xm; int ym;}pp[4*maxn];void build(int le,int ri,int tot){ if(le==ri) { pp[tot].min=height[le]; pp[tot].xm=min(sa[le],sa[le-1]); pp[tot].ym=max(sa[le],sa[le-1]); return ; } int mid; mid=(le+ri)/2; build(le,mid,2*tot); build(mid+1,ri,2*tot+1); pp[tot].min=min(pp[2*tot].min,pp[2*tot+1].min); pp[tot].xm=min(pp[2*tot].xm,pp[2*tot+1].xm); pp[tot].ym=max(pp[2*tot].ym,pp[2*tot+1].ym); return ;}int query1(int le,int ri,int tot,int ll,int rr){ int p,q; p=100000000; q=100000000; if(le>ri) return 0; if(le<=ll&&ri>=rr) { return pp[tot].min; } int mid; mid=(ll+rr)/2; if(le<=mid) { p=query1(le,ri,2*tot,ll,mid); } if(ri>mid) { q=query1(le,ri,2*tot+1,mid+1,rr); } if(p==100000000&&q==100000000) return 0; return min(p,q);}int query2(int le,int ri,int tot,int ll,int rr){ int p,q; p=100000000; q=100000000; if(le>ri) return 0; if(le<=ll&&ri>=rr) { return pp[tot].xm; } int mid; mid=(ll+rr)/2; if(le<=mid) { p=query2(le,ri,2*tot,ll,mid); } if(ri>mid) { q=query2(le,ri,2*tot+1,mid+1,rr); } if(p==100000000&&q==100000000) return 0; return min(p,q);}int query3(int le,int ri,int tot,int ll,int rr){ int p,q; p=100000000; q=100000000; if(le>ri) return 0; if(le<=ll&&ri>=rr) { return pp[tot].ym; } int mid; mid=(ll+rr)/2; if(le<=mid) { p=query3(le,ri,2*tot,ll,mid); } if(ri>mid) { q=query3(le,ri,2*tot+1,mid+1,rr); } if(p==100000000&&q==100000000) return 0; return max(p,q);}bool vis[1005][1005];bool ha[mod];LL s[10005];LL jie[10005];int get_pow(int n,int m){ LL p,k; p=1; k=n; while(m>0){ if(m&1){ p=p*k; p%=mod; } k=k*k; k%=mod; m>>=1; } return p;}void init(void){ int i; jie[0]=1; jie[1000]=get_pow(31,mod-1000-1); for(i=999;i>=1;i--){ jie[i]=jie[i+1]*31; jie[i]%=mod; }}int main(){ int i,n,j,p,f,u,x,y; int ss; LL q,v; init(); while(1) { scanf("%s",a); if(a[0]=='#') break; n=(int)strlen(a); v=1; for(i=0;i<n;i++) { r[i]=a[i]-'a'+1; if(i==0) s[i]=r[i]; else{ s[i]=s[i-1]+r[i]*v; s[i]%=mod; } v=v*31; v%=mod; } r[n]=0;//为了使rank从1开始,防止height[rank[i]-1]越界。 da(r,sa,n+1,20002); calheight(r,sa,n); ss=0; for(i=1;i<n;i++){ j=2; while(j<=n){ x=-1; y=1000000000; while(j<=n&&height[j]>=i){ x=max(x,sa[j]); x=max(x,sa[j-1]); y=min(y,sa[j]); y=min(y,sa[j-1]); j++; } if(x!=-1&&y<=1000000&&x-y>=i){ ss++; } j++; } } printf("%d\n",ss); } return 0;}
0 0
- HDU 5008 (2014西安网络赛第二题)后缀数组
- HDU 5008西安网络赛B题:后缀数组求第k小子串
- 后缀数组(2014西安网络赛)hdu5008
- hdu5008 Boring String Problem,2014西安网络赛B题,后缀数组,RMQ
- hdu 5030(2014广州网络赛)后缀数组+二分!
- 2014西安网络预选赛1002(后缀数组求第K大的子串)hdu5008
- hdu 5011 Game(2014 西安网络赛)
- hdu 5012 2014西安网络赛
- HDU 5007 Post Robot(西安网络赛A题)
- HDU 5009 Paint Pearls(西安网络赛C题)
- HDU 5011 Game(西安网络赛E题)
- HDU 5014 Number Sequence(西安网络赛H题)
- HDU 5015 233 Matrix(西安网络赛I题)
- HDU 5012 Dice(西安网络赛F题)
- HDU 5017 Ellipsoid(西安网络赛K题)
- hdu-5442(后缀数组,2015网络赛长春赛区)
- HDU 5008 Boring String Problem(西安网络赛B题)
- HDU 5012 Dice (2014年西安赛区网络赛F题)
- java核心技术卷之异常,断言学习笔记
- Ubuntu12.04下安装Hadoop2.4.0 (单机模式)
- scanf函数
- 2014年9月英语总结
- 程序员求职之道(《程序员面试笔试宝典》)之程序员如何保持身心健康?
- HDU 5008 (2014西安网络赛第二题)后缀数组
- jquery mobile 按钮大小修改
- struct event无定义?
- Java基本学习小结
- 程序员求职之道(《程序员面试笔试宝典》)之程序员的健康谁来保证?
- VB.NET与C# 语法区别展示
- U-BOOT LCD分析
- hdu4718 RK
- 找球号(三)