【poj3415-长度不小于k的公共子串个数】后缀数组+单调栈
2016-09-28 20:05
387 查看
这题曾经用sam打过,现在学sa再来做一遍。
基本思路:计算A所有的后缀和B所有后缀之间的最长公共前缀。
分组之后,假设现在是做B的后缀。前面的串能和当前的B后缀产生的公共前缀必定是从前往后单调递增的,每次与h[i]取min时必定将栈尾一些长的全部取出来,搞成一个短的。
所以就开一个栈,栈里存的是长度,同时存一下它的出现此处cnt。
注意各种细节啊。。
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> using namespace std; typedef long long LL; const int N=2*100010; int K,sl,cl,sa ,rk ,Rs ,wr ,y ,h ; LL sk ,cnt ; char s ,c ; void get_sa(int m) { for(int i=1;i<=cl;i++) rk[i]=c[i]; for(int i=1;i<=m;i++) Rs[i]=0; for(int i=1;i<=cl;i++) Rs[rk[i]]++; for(int i=1;i<=m;i++) Rs[i]+=Rs[i-1]; for(int i=cl;i>=1;i--) sa[Rs[rk[i]]--]=i; int ln=1,p=0; while(p<cl) { int k=0; for(int i=cl-ln+1;i<=cl;i++) y[++k]=i; for(int i=1;i<=cl;i++) if(sa[i]>ln) y[++k]=sa[i]-ln; for(int i=1;i<=cl;i++) wr[i]=rk[y[i]]; for(int i=1;i<=m;i++) Rs[i]=0; for(int i=1;i<=cl;i++) Rs[wr[i]]++; for(int i=1;i<=m;i++) Rs[i]+=Rs[i-1]; for(int i=cl;i>=1;i--) sa[Rs[wr[i]]--]=y[i]; for(int i=1;i<=cl;i++) wr[i]=rk[i]; for(int i=cl+1;i<=cl+ln;i++) wr[i]=0; p=1;rk[sa[1]]=1; for(int i=2;i<=cl;i++) { if(wr[sa[i]]!=wr[sa[i-1]] || wr[sa[i]+ln]!=wr[sa[i-1]+ln]) p++; rk[sa[i]]=p; } ln*=2,m=p; } sa[0]=0,rk[0]=0; } void get_h() { int k=0,j; for(int i=1;i<=cl;i++) if(rk[i]!=1) { j=sa[rk[i]-1]; if(k) k--; while(c[i+k]==c[j+k] && i+k<=cl && j+k<=cl) k++; h[rk[i]]=k; } h[1]=0; } void init() { int i,tl;cl=0; scanf("%s",s+1); tl=strlen(s+1);sl=tl; for(i=1;i<=sl;i++) c[++cl]=s[i]; scanf("%s",s+1); tl=strlen(s+1); c[++cl]='#'; for(i=1;i<=sl;i++) c[++cl]=s[i]; } bool check(int x,int tmp) { if(tmp==0) return (x<=sl) ? 0:1; else return (x<=sl) ? 1:0; } LL solve(int tmp) { int tot=0; LL sum=0,ans=0; memset(sk,0,sizeof(sk)); memset(cnt,0,sizeof(cnt)); for(int i=1;i<=cl;i++) { if(h[i]<K) { for(int j=1;j<=tot;j++) cnt[j]=0; tot=0;sum=0; } else { int tcnt=0,tsum=0; while(sk[tot] > h[i]-K+1) { tcnt+=cnt[tot]; tsum+=cnt[tot]*sk[tot]; sk[tot]=0,cnt[tot]=0; tot--; } if(tcnt) { sk[++tot]=h[i]-K+1; cnt[tot]=tcnt; sum=sum-tsum+tcnt*sk[tot]; } if(check(sa[i],tmp)) ans+=sum; } if(!check(sa[i],tmp) && (cl-sa[i]+1>=K)) { sk[++tot]=(cl-sa[i]+1)-K+1; cnt[tot]++; sum+=sk[tot]; } } return ans; } int main() { freopen("a.in","r",stdin); freopen("me.out","w",stdout); while(1) { scanf("%d",&K); if(!K) return 0; init(); get_sa(200); get_h(); // for(int i=1;i<=cl;i++) printf("%d ",sa[i]);printf("\n"); // for(int i=1;i<=cl;i++) printf("%d ",rk[i]);printf("\n"); // for(int i=1;i<=cl;i++) // { // for(int j=sa[i];j<=cl;j++) printf("%c",c[j]);printf("\n"); // } printf("%I64d\n",solve(0)+solve(1)); } return 0; }
相关文章推荐
- 长度不小于 k 的公共子串的个数(poj3415)
- poj3415之长度不小于k的公共子串个数
- POJ 3415 Common Substrings(长度不小于k 的公共子串的个数--后缀数组+单调栈优化)
- poj 3415 :长度不小于 k 的公共子串的个数(后缀数组+单调栈)
- 【POJ 3415】Common Substrings 长度不小于k的公共子串的个数
- POJ 3415 Common Substrings (求长度不小于k的公共子串的个数)
- 后缀数组(长度不小于k的公共子串的个数)
- poj 3415 后缀数组 两个字符串中长度不小于 k 的公共子串的个数
- POJ-Common Substrings(后缀数组-长度不小于 k 的公共子串的个数)
- POJ 3415 Common Substrings(长度不小于K的公共子串的个数+后缀数组+height数组分组思想+单调栈)
- hdu 3415 后缀数组 长度不小于 k 的公共子串的个数
- POJ 3415 Common Substrings (后缀数组,长度不小于k的公共子串的个数)
- 【poj3294-不小于k个字符串中最长公共子串】后缀数组
- (Relax 后缀数组1.3)POJ 3415 Common Substrings(求串A和串B中长度不小于k的公共子串数)
- 后缀数组(长度不小于k的公共子串的个数)
- POJ 3415-Common Substrings(后缀数组+单调栈-公共子串的长度)
- POJ - 3415 Common Substrings(后缀数组求长度不小于 k 的公共子串的个数+单调栈优化)
- POJ 3415 求两个字符串间长度不小于k的公共子串的个数
- POJ - 3415 Common Substrings(后缀数组求长度不小于 k 的公共子串的个数+单调栈优化)
- 后缀数组(多个穿的最长公共子串)+KMP+poj3080