【POJ3415】Common Substrings 后缀自动机

来源:互联网 发布:java怎么定义一个方法 编辑:程序博客网 时间:2024/04/29 13:26

转载请注明出处:http://blog.csdn.net/vmurder/article/details/42710069
其实我就是觉得原创的访问量比未授权盗版多有点不爽233。。。

题意:

给两个串,问有多少长度大于等于K的公共子串(位置不同也算一对)

题解:

后缀自动机DP

对第一个串建立后缀自动机,然后做一些预处理,

然后拿第二个串在后缀自动机上跑,到每个节点加一次贡献。

但是这样需要每个点往parent树上跑一遍,会TLE,所以可以加个lazy。

然后代码中有两次运用到拓扑序来从子向父推DP值。

呃,说得乱糟糟的。


Orz No_stop

不妨来看看他的博客:http://blog.csdn.net/no__stop/article/details/11830521


代码:

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define N 101000#define T 52using namespace std;int pa[N<<1],son[N<<1][T],dep[N<<1];int cnt,last;char Sa[N],Sb[N];int sa[N],sb[N],lena,lenb;inline int new_node(int step){dep[++cnt]=step;return cnt;}inline void SAM(int alp) // 把A串建立后缀自动机{int p=new_node(dep[last]+1);int u=last;while(u&&!son[u][alp])son[u][alp]=p,u=pa[u];if(!u)pa[p]=1;else {int v=son[u][alp];if(dep[v]==dep[u]+1)pa[p]=v;else {int nv=new_node(dep[u]+1);memcpy(son[nv],son[v],sizeof son[nv]);pa[nv]=pa[v],pa[v]=pa[p]=nv;while(u&&son[u][alp]==v)son[u][alp]=nv,u=pa[u];}}last=p;}int ts[N<<1],pos[N<<1],cont[N<<1],flag[N<<1];void Sort(){ // 基数排序使得SAM的节点在pos内呈拓扑序int i;for(i=1;i<=cnt;i++)ts[i]=0;for(i=1;i<=cnt;i++)ts[dep[i]]++;for(i=1;i<=cnt;i++)ts[i]+=ts[i-1];for(i=1;i<=cnt;i++)pos[ts[dep[i]]--]=i;}void Cal(){ // 计算从一个节点的Right集合元素数目int p=1,i;for(i=0;i<lena;i++){int alp=sa[i];cont[son[p][alp]]++;p=son[p][alp];}for(i=cnt;i>=1;i--){ // topo向上推int q=pos[i];cont[pa[q]]+=cont[q];}}long long ans;int limit;void solve(){ //在A串的SAM上跑B串int i;int temp=0,p=1;ans=0;for(i=0;i<lenb;i++){int d=sb[i];if(son[p][d]){ // temp表示当前串最长长度temp++;p=son[p][d];}else{// 失配while(p&&!son[p][d])p=pa[p];if(!p)temp=0,p=1; // 彻底失配else temp=dep[p]+1,p=son[p][d]; // 只退一部分}int q=p;if(temp>=limit){ // 匹配部分足够长ans+=(long long)(temp-max(limit,dep[pa[p]]+1)+1)*cont[p];if(limit<=dep[pa[p]])flag[pa[p]]++;}// 没有else。。显然不够就没用}for(i=cnt;i>=1;i--){// 往回推标记p=pos[i];ans+=(long long)flag[p]*(dep[p]-max(limit,dep[pa[p]]+1)+1)*cont[p];if(limit<=dep[pa[p]])flag[pa[p]]+=flag[p];}}void init(){memset(flag,0,sizeof flag);memset(cont,0,sizeof cont);memset(son,0,sizeof son);memset(pa,0,sizeof pa);last=cnt=1;}int main(){//freopen("test.in","r",stdin);while(scanf("%d",&limit),limit){init();scanf("%s%s",Sa,Sb);lena=strlen(Sa),lenb=strlen(Sb);for(int i=0;i<lena;i++){if('a'<=Sa[i]&&Sa[i]<='z')sa[i]=Sa[i]-'a';else sa[i]=Sa[i]-'A'+26;SAM(sa[i]);}for(int i=0;i<lenb;i++){if('a'<=Sb[i]&&Sb[i]<='z')sb[i]=Sb[i]-'a';else sb[i]=Sb[i]-'A'+26;}Sort();Cal();solve();cout<<ans<<endl;}}


0 0
原创粉丝点击