[后缀数组+枚举] hdu 4622 Reincarnation
来源:互联网 发布:自然语言处理 源码 编辑:程序博客网 时间:2024/05/24 01:55
题意:求一个字符串中,[a,b]内的不同子串数是多少。
思路:跟之前的求整个字符串中的不同子串数的方法一样,总的个数减去重复个数。
当然这题显然不能截取一段做一次DA,这样是超时的。
当然也不能选完在排序,我们其实可以种一个方法规避排序。
首先我们知道sa是排好序的了,那么我们只要标记一下[a,b]之间的ra[i],也就是sa里的位置。
这样我们遍历一遍sa,计算一下那些被标记的位置的lcp就好了!
代码:
#include"cstdlib"#include"cstdio"#include"cstring"#include"cmath"#include"queue"#include"algorithm"#include"iostream"#include"map"using namespace std;#define N 20020int wa[N],wb[N],wv[N],wws[N];int sa[N],ra[N],height[N],Log[N];int v[N];int cmp(int *r,int a,int b,int l){ return r[a]==r[b]&&r[a+l]==r[b+l];}void da(int n,int m){ int i,j,p,*x=wa,*y=wb; for(i=0; i<m; i++) wws[i]=0; for(i=0; i<n; i++) wws[x[i]=v[i]]++; for(i=1; i<m; i++) wws[i]+=wws[i-1]; for(i=n-1; i>=0; i--) sa[--wws[x[i]]]=i; for(j=1,p=1; p<n; j*=2,m=p) { for(i=n-j,p=0; 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++) wws[i]=0; for(i=0; i<n; i++) wws[wv[i]]++; for(i=1; i<m; i++) wws[i]+=wws[i-1]; for(i=n-1; i>=0; i--) sa[--wws[wv[i]]]=y[i]; for(swap(x,y),p=1,i=1,x[sa[0]]=0; i<n; i++) x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++; } return ;}void gethei(int n){ int i,j,k=0; for(i=1; i<=n; i++) ra[sa[i]]=i; for(i=0; i<n; i++) { if(k) k--; j=sa[ra[i]-1]; while(v[i+k]==v[j+k]) k++; height[ra[i]]=k; } return ;}char fuck[12345];int dp[N][30];void rmqinit(int n){ int m=Log[n]; int i,j; for(i=1; i<=n; i++) dp[i][0]=height[i]; for(i=1; i<=m; i++) { for(j=1; j+(1<<i)-1<=n; j++) dp[j][i]=min(dp[j][i-1],dp[j+(1<<i>>1)][i-1]); } return ;}int lcp(int a,int b){ a=ra[a]; b=ra[b]; if(a>b) swap(a,b); a++; int m=Log[b-a+1]; return min(dp[a][m],dp[b-(1<<m)+1][m]);}int main(){ int t,i; Log[0]=-1; for(i=1; i<=N; i++) Log[i]=(i&(i-1))?Log[i-1]:Log[i-1]+1; cin>>t; while(t--) { scanf("%s",fuck); int n=strlen(fuck); for(i=0; i<n; i++) v[i]=fuck[i]; v[n]=0; da(n+1,550); gethei(n); rmqinit(n); int q; cin>>q; while(q--) { int x,y; scanf("%d%d",&x,&y); int ans=(y-x+1)*(1+y-x+1)/2; //总的长度 int tep[2234]; for(i=0; i<=n; i++) tep[i]=0; //标记清零 for(i=x-1; i<=y-1; i++) tep[ra[i]]=1; //标记哪些出现过 int last=-1; //因为第一个不算 标记是否是第一个 int d=0; //d表示在当前位置之前的最长的公共子串长度 for(i=1; i<=n; i++) //遍历sa { if(tep[i]) { if(last!=-1) { int z=lcp(sa[last],sa[i]); d=min(d,z); //对于所能提供的长度,d和lcp取最小 d=max(d,min(z,y-sa[last])); //对于最长的长度,取d与(lcp与前一个后缀长度的最小值)的最大值 ans-=min(d,y-sa[i]); //重复的则是 d与当前长度的最小值 } last=i; } } printf("%d\n",ans); } } return 0;}
0 0
- [后缀数组+枚举] hdu 4622 Reincarnation
- Hdu 4622 Reincarnation 后缀数组/后缀自动机
- hdu 4622 Reincarnation(后缀数组)
- hdu 4622 Reincarnation(后缀数组)
- HDU 4622 Reincarnation(后缀数组+ST)
- hdu 4622 Reincarnation(后缀数组|后缀自动机|KMP)
- HDU 4622 Reincarnation 后缀数组 或 后缀自动机
- hdu 4622 Reincarnation (后缀自动机)
- hdu 4622 Reincarnation (后缀自动机)
- HDU 4622 Reincarnation 后缀自动机
- hdu 4622 Reincarnation(后缀树组求子串个数)
- HDU 4622 Reincarnation(后缀自动机)
- HDU 4622 Reincarnation( 任意区间子串的长度, 后缀数组+RMQ)
- HDU 4622 Reincarnation (区间不相同子串个数:字符串哈希 | 后缀数组 | 后缀自动机)
- hdu 4622 Reincarnation(后缀自动机,入门级)
- [后缀自动机 模板题 || 字符串Hash] HDU 4622 Reincarnation
- HDU 4622 Reincarnation
- HDU-4622-Reincarnation
- 计算从某个日期开始往前或往后天数的日期
- RMAN备份过程中会写脏块吗?
- Introduction to Quartz
- 关于树的一些操作
- 【转】Android中关于DatePickerDialog与TimePickerDialog的结合使用
- [后缀数组+枚举] hdu 4622 Reincarnation
- UIImage 图片处理:截图,缩放,设定大小,存储
- linux 块设备总结
- 同学帮改肤色检测(未完成版)
- WF4.0——升级技能:泛型应用
- webService开发笔记(二)
- 火溶CEO王伟峰:Unity3D手机网游开发
- "DataTable是System.DataTable和Excel.DataTable 之间的不明确的引用 "问题的解决办法
- 回拨吸费电话 打工不如创业 加值电话平台