字符串(后缀数组):POJ 3415 Common Substrings
2016-03-18 22:32
429 查看
Common SubstringsDescriptionA substring of a string T is defined as:T(i, k)=TiTi+1...Ti+k-1, 1≤i≤i+k-1≤|T|.
Given two strings A, B and one integer K, we define S, a set of triples (i, j, k):S = {(i, j, k) | k≥K, A(i, k)=B(j, k)}.
You are to give the value of |S| for specific A, B and K.InputThe input file contains several blocks of data. For each block, the first line contains one integer K, followed by two lines containing strings A and B, respectively. The input file is ended by K=0.1 ≤ |A|, |B| ≤ 105
1 ≤ K ≤ min{|A|, |B|}
Characters of A and B are all Latin letters.OutputFor each case, output an integer |S|.Sample Input
Sample Output
Given two strings A, B and one integer K, we define S, a set of triples (i, j, k):S = {(i, j, k) | k≥K, A(i, k)=B(j, k)}.
You are to give the value of |S| for specific A, B and K.InputThe input file contains several blocks of data. For each block, the first line contains one integer K, followed by two lines containing strings A and B, respectively. The input file is ended by K=0.1 ≤ |A|, |B| ≤ 105
1 ≤ K ≤ min{|A|, |B|}
Characters of A and B are all Latin letters.OutputFor each case, output an integer |S|.Sample Input
2 aababaa abaabaa 1 xx xx 0
Sample Output
22 5 这道题呃,有些考验程序实践能力。 题意:对于给定的两个字符串和一个整数K,求两个字符串长度大于等于K的公共子串数目。 将两个字符串接起来,中间用一个特殊字符隔开,枚举Lcp,暴力枚举是O(n³)的,死活都不可能过。 这是我们想:能否使用以前枚举的信息?所以正解就出来了:单调栈优化! 具体咋打就看代码吧~~~
#include <iostream> #include <cstring> #include <cstdio> using namespace std; const int maxn=400010; char S[maxn]; int sa[maxn],r[maxn],rank[maxn],lcp[maxn]; int Wv[maxn],Ws[maxn],Wa[maxn],Wb[maxn],len; bool cmp(int *p,int a,int b,int l){ return p[a]==p[b]&&p[a+l]==p[b+l]; } void DA(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;m=p,j<<=1){ 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<m;i++)Ws[i]=0; for(i=0;i<n;i++)++Ws[Wv[i]=x[y[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,i=1,p=1,x[sa[0]]=0;i<n;i++) x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++; } } void Lcp(int n){ int i,j,k=0; for(i=1;i<=n;i++)rank[sa[i]]=i; for(i=0;i<n;lcp[rank[i++]]=k) for(k?--k:k,j=sa[rank[i]-1];r[i+k]==r[j+k];++k); } int s[maxn][2]; int main(){ int n,k; while(~scanf("%d",&k)&&k){ scanf("%s",S); n=strlen(S);S ='%'; scanf("%s",S+n+1); len=strlen(S); for(int i=0;i<len;i++) r[i]=S[i]; r[len]=0; DA(len+1,128); Lcp(len); int cnt=0; long long ans=0,sum=0; for(int i=1;i<=len;i++){ if(lcp[i]<k){ sum=0;cnt=0; continue; } int tot=0; if(sa[i-1]>n){ sum+=lcp[i]-k+1; tot++; } while(cnt&&s[cnt][0]>=lcp[i]){ tot+=s[cnt][1]; sum-=1ll*s[cnt][1]*(s[cnt][0]-lcp[i]); cnt--; } s[++cnt][0]=lcp[i]; s[cnt][1]=tot; if(sa[i]<n)ans+=sum; } cnt=0;sum=0; for(int i=1;i<=len;i++){ if(lcp[i]<k){ sum=0;cnt=0; continue; } int tot=0; if(sa[i-1]<n){ sum+=lcp[i]-k+1; tot++; } while(cnt&&s[cnt][0]>=lcp[i]){ tot+=s[cnt][1]; sum-=1ll*s[cnt][1]*(s[cnt][0]-lcp[i]); cnt--; } s[++cnt][0]=lcp[i]; s[cnt][1]=tot; if(sa[i]>n)ans+=sum; } printf("%lld\n",ans); } return 0; }
相关文章推荐
- [leetcode 244] Shortest Word Distance II------------字典中两个字符串的最短距离
- (9)Python爬虫——下载PDF
- 算法题:1的数目
- c++面试题【转】
- 使用压测工具ab实现搭建的页面压测
- 树的完整实现--遍历--应用
- Vmware vSphere 6.0之ESXI安装配置
- Android使用sd卡保存读取数据
- 151. Reverse Words in a String
- Boost环境配置及遇到的问题解决方案
- openwrt 显示系统版本和GCC的版本
- (整理)SQL server 2012 中文乱码与5030错误
- << >>
- 11. 接口和抽象类区别
- bzoj 2005: [Noi2010]能量采集
- <我的C++程序>简单的学生信息管理系统
- 最长上升子序列、最长公共上升子序列
- Linux系统程序包管理工具 RPM
- 2016蓝桥杯假期任务之《打印十字图》
- android学习——activity实现动画切换