hdu5008-Boring String Problem(后缀数组专题)

本文深入解析 BoringStringProblem 的解题逻辑,通过后缀数组的运用,详细阐述如何求所有子串并按字典序排序,进而解决查询第 K 个子串的问题。附带完整代码实现,帮助读者理解后缀数组在字符串排序中的应用。

Boring String Problem 

题目就是要将一个字符串所有的子串按照字典序顺序排好后,询问第K个子串(即输出子串的开始和结尾——L && R),当时我就觉得这道题很像后缀数组,因为后缀数组最注重的就是相同前缀,最最典型的就是它是按照字典序排列的!可是,后缀数组会打乱原有的字符串的排列顺序,也就是sa[i]!=i,当时我就迷糊了,现在想来,它主要是这么几个思考步骤:
1.如何求所有子串,还得有序 后缀数组里将所有后缀排序后,每个后缀suffix(i)所产生的不重复后缀个数 = n - sa[i] - height[i] ; 前者 n - sa[i] 是后缀长度,减去重复长度height[i],得到的就是新产生的长度,sub[i] 表示 从第一个后缀到第i个后缀总共产生的子串数(它们都是已经排好序的)
2.如何查询,这是个大问题,以"aaa"为例,如果你查询第0个子串,我们直接查询就会得到答案【3,3】因为在后缀数组里,“a\0” > "aaa\0" 所以说,我们还要处理,处理方法就是在 i - n 里找sa的最小值(设为j)而且他要满足 i-j的公共前缀>=查询子串的长度。用二分查找或是暴力都ok,但是查找第K个子串所在后缀就得用二分,不然会超时。
做题总结: 
a) 位运算尽量保证运算是统一的数据类型,而且要注意打括号;
b) 给变量命名,记得不要和系统或者自己已经使用过的变量名重复,也要记得初始化
c)记得杭电用的是I64d! 
好开心我开始有意识思考后缀数组了,这证明着我慢慢开始脱离模板思考了微笑

代码如下:
#include 
   
    
#include 
    
     
#include 
     
      
#include 
      
       
#include 
       
        
#include 
        
          #include 
         
           #include 
          
            #include 
           
             #include 
             #define Na 100010 using namespace std; int wa[Na],wb[Na],wss[Na],wv[Na]; int rankk[Na],height[Na]; int cmp(int *r,int a,int b,int l) { return (r[a]==r[b]) && (r[a+l]==r[b+l]); } void da(char *r,int *sa,int n,int m) { int i,j,p,*x=wa,*y=wb,*t; for(i=0; i
             
              =0; i--) sa[--wss[x[i]]]=i; for(j=1,p=1; p
              
               =j) y[p++]=sa[i]-j; for(i=0; i
               
                =0; i--) sa[--wss[wv[i]]]=y[i]; for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1; i
                
                 = commonlength ) { if( sa[j] < l ) { l = sa[j] ; } j++ ; } l = l + 1 ; r = l + commonlength - 1 ; /**交的时候千万记得改为I64d*/ printf( "%lld %lld\n" , l , r ) ; } } } return 0; } 
                
               
              
             
           
          
         
        
       
      
     
    
   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值