poj 3415 Common Substrings (后缀数组+单调栈)
2016-12-29 09:09
495 查看
Common Substrings
A 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. Input The 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. Output For each case, output an integer |S|. Sample Input 2 aababaa abaabaa 1 xx xx 0 Sample Output 22 5 Source POJ Monthly--2007.10.06, wintokk |
[Discuss]
题目大意:长度不小于K的公共子串个数。
基本的思路是求字符串A的所有后缀和字符串B的所有后缀的最长公共前缀,然后将>=k的部分全部加起来。
将两个串连接,中间用分割符连接。按height值分组后,问题就转化成了快速求一个组中分属两串的后缀中有能产生多少长度不小于K的子串。我们先以A为列,我们遇到一个A的后缀就需要统计他与前面B的后缀产生的不小于K的子串的个数,如果单看一个A的后缀和一个B的后缀,产生的个数就是(height-k+1),我们现在用一个单调栈维护栈中的height值单调递增,如果新加入的height>st[top]的话,也就是说当前位置与前面B的后缀能产生的贡献是不变的,所以直接将之前记录的值sum计入答案即可。如果当前数比栈顶元素小了,那么在的基础上(height-k+1)的值就会相应的减小,减小的值为(height-st[top])*cnt[top](cnt[top]记录的是到栈顶代表的位置到前一个栈元素之间有多少B的后缀),所以我们就要弹栈。反过来对B也这么做一遍就可以了。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define N 1000003 #define LL long long using namespace std; int rank ,sa ,a ,b ,xx ,yy ,*x,*y,height ; int n,len,m,p,st ,top,k,cnt ; LL sum; char s ; int init() { memset(b,0,sizeof(b)); memset(sa,0,sizeof(sa)); memset(rank,0,sizeof(rank)); } int cmp(int i,int j,int l) { return y[i]==y[j]&&(i+l>len?-1:y[i+l])==(j+l>len?-1:y[j+l]); } void get_SA() { x=xx; y=yy; m=200; for (int i=1;i<=len;i++) b[x[i]=a[i]]++; for (int i=1;i<=m;i++) b[i]+=b[i-1]; for (int i=len;i>=1;i--) sa[b[x[i]]--]=i; for (int k=1;k<=len;k<<=1) { p=0; for (int i=len-k+1;i<=len;i++) y[++p]=i; for (int i=1;i<=len;i++) if (sa[i]>k) y[++p]=sa[i]-k; for (int i=1;i<=m;i++) b[i]=0; for (int i=1;i<=len;i++) b[x[y[i]]]++; for (int i=1;i<=m;i++) b[i]+=b[i-1]; for (int i=len;i>=1;i--) sa[b[x[y[i]]]--]=y[i]; swap(x,y); p=2; x[sa[1]]=1; for (int i=2;i<=len;i++) x[sa[i]]=cmp(sa[i-1],sa[i],k)?p-1:p++; if (p>len) break; m=p+1; } p=0; for (int i=1;i<=len;i++) rank[sa[i]]=i; for (int i=1;i<=len;i++) { if (rank[i]==1) continue; int j=sa[rank[i]-1]; while (i+p<=len&&j+p<=len&&a[i+p]==a[j+p]) p++; height[rank[i]]=p; p=max(p-1,0); } } int main() { freopen("a.in","r",stdin); freopen("my.out","w",stdout); while (true) { init(); scanf("%d",&k); if (!k) break; scanf("%s",s+1); n=strlen(s+1); len=0; sum=0; for (int i=1;i<=n;i++) a[++len]=s[i]; a[++len]='$'; int mark=len; scanf("%s",s+1); n=strlen(s+1); for (int i=1;i<=n;i++) a[++len]=s[i]; get_SA(); top=0; sum=0; LL ans=0; //if (sa[1]<mark) st[++top]=1; for (int i=1;i<=len;i++) if (height[i]>=k) { int num=0; while (height[i]<=st[top]&&top) { sum+=(LL)(height[i]-st[top])*(LL)cnt[top]; num+=cnt[top]; top--; } st[++top]=height[i]; if (sa[i-1]>mark) { sum+=(LL)(height[i]-k+1); cnt[top]=num+1; } else cnt[top]=num; if (sa[i]<mark) ans+=sum; } else top=0,sum=0; top=0; sum=0; for (int i=1;i<=len;i++) if (height[i]>=k) { int num=0; while (height[i]<=st[top]&&top) { sum+=(LL)(height[i]-st[top])*(LL)cnt[top]; num+=cnt[top]; top--; } st[++top]=height[i]; if (sa[i-1]<mark) { sum+=(LL)(height[i]-k+1); cnt[top]=num+1; } else cnt[top]=num; if (sa[i]>mark) ans+=sum; // cout<<sum<<endl; } else top=0,sum=0; printf("%I64d\n",ans); } }
相关文章推荐
- poj 3415 Common Substrings(后缀数组+单调栈)
- poj_3415 后缀数组+单调栈
- [POJ 3415] Common Substrings (后缀数组+单调栈优化)
- POJ 3415 Common Substrings(后缀数组+单调栈)
- POJ 3415 Common Substrings(长度不小于k 的公共子串的个数--后缀数组+单调栈优化)
- poj 3415 :长度不小于 k 的公共子串的个数(后缀数组+单调栈)
- 【POJ】3415 Common Substrings 【后缀数组+单调栈】
- POJ 3415-Common Substrings(后缀数组+单调栈-公共子串的长度)
- POJ 3415 Common Substrings(后缀数组+单调栈)
- poj 3415 Common Substrings(后缀数组+单调栈)
- POJ 3415:Common Substrings 后缀数组+单调栈
- POJ 3415 Common Substrings(后缀数组+单调栈)
- POJ-3415-Common Substrings(后缀数组+单调栈)
- POJ 3415 后缀数组+单调栈
- POJ - 3415 Common Substrings 后缀数组+单调栈
- POJ 3415 Common Substrings ( 后缀数组+单调栈(那篇论文中的题目。多谢罗神给的的思路)
- poj 3415 Common Substrings(后缀数组+单调栈+dp)
- POJ - 3415 Common Substrings 后缀数组+单调栈+前缀和
- POJ 3415 Common Substrings <后缀数组+单调栈>
- POJ 3415 Common Substrings(长度不小于K的公共子串的个数+后缀数组+height数组分组思想+单调栈)