poj 3415 ( 后缀数组 长度不小于 k 的公共子串的个数)
来源:互联网 发布:百度关键词优化技巧 编辑:程序博客网 时间:2024/05/16 11:24
题意 :
给定两个字符串 A 和 B,求长度不小于 k 的公共子串的个数(可以相同)。
样例 1:A=“xx”,B=“xx”,k=1,长度不小于 k 的公共子串的个数是 5。
样例 2:
A = “aababaa”,B = “abaabaa”,k=2,长度不小于 k 的公共子串的个数是22。
思路 : 基本思路是计算 A 的所有后缀和 B 的所有后缀之间的最长公共前缀的长度,把最长公共前缀长度不小于 k 的部分全部加起来。比如样例2中 A的后缀4和B的后缀1的LCP为baa = 3 , 那么这里就有2个公共子串。因为起点是不一样的,所以最后结果就是直接把所有LCP( i , j ) >= k 的部分求和就可以了。当然,如果直接搞的话,是要O( n*n ) 的,铁定要超时。比较好的做法是,将连接起来的字符串根据 K ,讲height 分组 , 那么每组内 , 所有的LCP都是大于等于k , 那么我们要做的快速的统计出每组中长度不小于k的公共子串的个数。
那么对于每一组,用一个单调栈去维护,对于每个sa[i],我们把对应的height[i+1]的值加入到单调栈中,保证栈中的height值是递增的。每次出现一个B字符串中的后缀,就统计单调栈中有多少个A字符串中的子串长度大于等于k。那么如何统计呢?我维护了一个cnt域和sum域( 这个方法可能比较麻烦 ... 不过看了其他人的报告 ... 没看懂怎么处理的,就自己想了个笨方法 ) ,cnt域表示一个较小的height加入到单调栈中的时候删掉的元素的个数( 因为较小的height加入,当时比这个height大的就最多只能由当前height这个大小了,所以要把这些删掉的元素当成大小为height算),以及sum域表示从栈底到该元素A的子串中有多少个长度大于等于k的公共子串。
cnt就直接在元素加入栈的时候维护,sum 的维护根据前一个元素的sum来维护,即 sum = s[top-1].sum + cnt * ( height[i+1] - k + 1 )
为了方便计算,我维护的height值,其实是height-k+1
当遇到一个B字符串中的元素时,ans 加上 sum[top-1].sum 即可
当然,这个过程还要再做一遍,第二遍栈里面统计的是字符串B中的信息
#include <stdio.h> #include <string.h>#include <string>#include <vector>#include <iostream>#include <algorithm> using namespace std; #define maxn 200205int wa[maxn],wb[maxn],wv[maxn],wt[maxn]; typedef long long LL ;int cmp(int *r,int a,int b,int l) {return r[a]==r[b]&&r[a+l]==r[b+l];} 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++) wt[i]=0; for(i=0;i<n;i++) wt[x[i]=r[i]]++; for(i=1;i<m;i++) wt[i]+=wt[i-1]; for(i=n-1;i>=0;i--) sa[--wt[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++) wt[i]=0; for(i=0;i<n;i++) wt[wv[i]]++; for(i=1;i<m;i++) wt[i]+=wt[i-1]; for(i=n-1;i>=0;i--) sa[--wt[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++; } } int Rank[maxn],height[maxn]; void calheight(int *r,int *sa,int n){ int i , j , k = 0 ; for( i=1 ; i<=n ; i++ ) Rank[sa[i]]=i; for(i=0;i<n;i++) { if(k)k--; int j = sa[Rank[i]-1]; while(r[i+k]==r[j+k]) k++ ; height[Rank[i]] = k ; } return; } int r[maxn] , sa[maxn] ; char str[maxn] ;struct Node{int cnt ;int height ;LL sum ;Node(){}Node( int _cnt , int _height , LL _sum ){cnt = _cnt ;height = _height ;sum = _sum ;}};int top ;Node s[maxn] ;int main(){int k ;while( scanf( "%d" , &k ) != EOF ) {LL ans = 0 ;if( k == 0 ) break; scanf( "%s" , str ) ;int len1 = strlen( str ) ;str[len1] = '$' ; str[len1+1] = 0 ;scanf( "%s" , str + len1 + 1 ) ;int len = strlen( str ) ;for( int i = 0 ; i < len ; i ++ ) r[i] = str[i] ; r[len] = 0 ;da( r , sa , len + 1 , 200 ) ;calheight( r , sa , len ) ;top = 0 ;int cnt = 0 ;if( sa[1] < len1 ) cnt ++ ;if( sa[1] != len1 ) {s[top++] = Node( cnt , height[2] - k + 1 , height[2] - k + 1 ) ;}for( int i = 2 ; i <= len ; i ++ ) {if( sa[i] > len1 && top > 0 ) ans += max( (LL)0 , s[top-1].sum ) ;if( height[i] < k ) {top = 0 ;}if( sa[i] < len1 ) cnt = 1 ;else if( sa[i] > len1 )cnt = 0 ;else continue ;while( top > 0 && s[top-1].height >= height[i+1] - k + 1 ) {top -- ;cnt += s[top].cnt ;}LL tmp = (LL)cnt * ( height[i+1] - k + 1 ) ;if( top > 0 ) tmp += s[top-1].sum ;s[top++] = Node( cnt , height[i+1] - k + 1 , tmp ) ;}top = 0 ;cnt = 0 ;if( sa[1] > len1 ) cnt ++ ;if( sa[1] != len1 ) {s[top++] = Node( cnt , height[2] - k + 1 , height[2] - k + 1 ) ;}for( int i = 2 ; i <= len ; i ++ ) {if( sa[i] < len1 && top > 0 ) ans += max( (LL)0 , s[top-1].sum ) ;if( height[i] < k ) {top = 0 ;}if( sa[i] > len1 ) cnt = 1 ;else if( sa[i] < len1 )cnt = 0 ;else continue ;while( top > 0 && s[top-1].height >= height[i+1] - k + 1 ) {top -- ;cnt += s[top].cnt ;}LL tmp = (LL)cnt * ( height[i+1] - k + 1 ) ;if( top > 0 ) tmp += s[top-1].sum ;s[top++] = Node( cnt , height[i+1] - k + 1 , tmp ) ;}printf( "%lld\n" , ans ) ;}return 0 ;}
- poj 3415 ( 后缀数组 长度不小于 k 的公共子串的个数)
- hdu 3415 后缀数组 长度不小于 k 的公共子串的个数
- POJ - 3415 Common Substrings(后缀数组求长度不小于 k 的公共子串的个数+单调栈优化)
- POJ 3415 Common Substrings(长度不小于k 的公共子串的个数--后缀数组+单调栈优化)
- poj 3415 :长度不小于 k 的公共子串的个数(后缀数组+单调栈)
- 后缀数组(长度不小于k的公共子串的个数)
- 后缀数组(长度不小于k的公共子串的个数)
- POJ 3415 求两个字符串间长度不小于k的公共子串的个数
- POJ 3415 不小于k的公共子串的个数
- 长度不小于 k 的公共子串的个数(poj3415)
- poj3415之长度不小于k的公共子串个数
- (Relax 后缀数组1.3)POJ 3415 Common Substrings(求串A和串B中长度不小于k的公共子串数)
- poj 3415 长度超过K的公共子串个数
- POJ 题目3415 Common Substrings(后缀数组+栈,求可以匹配到的长度大于k的公共子串个数)
- POJ 3294 Life Forms(不小于k个字符串中的最长子串 后缀数组)
- poj 3294 ( 后缀数组 不小于 k 个字符串中的最长子串 )
- POJ 3294 后缀数组:求不小于k个字符串中的最长子串
- poj 3294 不小于 k 个字符串中的最长子串(后缀数组+二分)
- [Tomcat]JDBC Driver has been forcibly unregistered
- struts2 编码拦截器
- [文件系统]文件系统学习笔记(三)---目录项缓存dentry
- C#获得本机物理网卡的MAC地址
- Bootstrap
- poj 3415 ( 后缀数组 长度不小于 k 的公共子串的个数)
- stackless + twisted 编程模型
- 基于Android/机顶盒/pc高质量视频通话及手机直播源码转让
- 原来有种方法叫继承
- Android 测试 Appium、Robotium、monkey等框架或者工具对比
- ISE中FPGA的实现流程
- 公司项目总结
- Android中对Json数据解析实例(网络访问的问题)
- poj1222 EXTENDED LIGHTS OUT 高斯消元