poj3415 Common Substrings(后缀自动机)

A substring of a string T is defined as:

 

Tik)= TiTi +1... Ti+k -1, 1≤ i≤ i+k-1≤| T|.

 

Given two strings AB and one integer K, we define S, a set of triples (ijk):

 

S = {( ijk) | k≥ KAik)= Bjk)}.

 

You are to give the value of |S| for specific AB 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





对第一个串建立自动机,然后让第二个串在上面跑,记录一下到每个状态时的匹配的长度,一个状态是很多后缀串的集合,我们只需要当前状态中大于等于K 小于等于匹配长度的串然后如果fa有长度也大于等于k的串的话,那也可以去为了避免每次都要向上找fa,打一个lazy标记一波,最后在一遍更新就行了。



 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define ri register int
 6 using namespace std;
 7 const int N=2e5+5;
 8 typedef long long ll;
 9 int k,n;
10 char s[N];
11 inline int calc(char c){return c>=‘a‘&&c<=‘z‘?c-‘a‘:c-‘A‘+26;}
12 struct SAM{
13     int tot,rt,last,len[N],link[N],son[N][60],siz[N],lz[N],cnt[N],rk[N];
14     inline void init(){
15         memset(len,0,sizeof(len)),memset(siz,0,sizeof(siz)),memset(rk,0,sizeof(rk)),memset(son,0,sizeof(son));
16         memset(link,0,sizeof(link)),memset(cnt,0,sizeof(cnt)),memset(lz,0,sizeof(lz)),tot=last=rt=1,len[0]=-1;
17     }
18     inline void expend(int x){
19         int p=last,np=++tot;
20         siz[last=np]=1,len[np]=len[p]+1;
21         while(p&&!son[p][x])son[p][x]=np,p=link[p];
22         if(!p){link[np]=rt;return;}
23         int q=son[p][x],nq;
24         if(len[q]==len[p]+1){link[np]=q;return;}
25         len[nq=++tot]=len[p]+1,memcpy(son[nq],son[q],sizeof(son[q])),link[nq]=link[q];
26         while(p&&son[p][x]==q)son[p][x]=nq,p=link[p];
27         link[q]=link[np]=nq;
28     }
29     inline void topsort(){
30         for(ri i=1;i<=tot;++i)++cnt[len[i]];
31         for(ri i=1;i<=last;++i)cnt[i]+=cnt[i-1];
32         for(ri i=1;i<=tot;++i)rk[cnt[len[i]]--]=i;
33         for(ri i=tot;i;--i)siz[link[rk[i]]]+=siz[rk[i]];
34     }
35     inline void query(){
36         topsort();
37         int p=1,nowlen=0;
38         ll ans=0;
39         for(ri i=1;i<=n;++i){
40             int x=calc(s[i]);
41             if(son[p][x])p=son[p][x],++nowlen;
42             else{
43                 while(p&&!son[p][x])p=link[p];
44                 if(!p)p=1,nowlen=0;
45                 else nowlen=len[p]+1,p=son[p][x];
46             }
47             if(nowlen>=k){
48                 ans+=(ll)(nowlen-max(k,len[link[p]]+1)+1)*siz[p];
49                 if(len[link[p]]>=k)++lz[link[p]];
50             }
51         }
52         for(ri i=tot;i;--i){
53             p=rk[i];
54             ans+=(ll)lz[p]*siz[p]*(len[p]-max(k,len[link[p]]+1)+1);
55             if(len[link[p]]>=k)lz[link[p]]+=lz[p];
56         }
57         cout<<ans<<‘\n‘;
58     }
59 }sam;
60 int main(){
61     while(scanf("%d",&k),k){
62         scanf("%s",s+1),n=strlen(s+1),sam.init();
63         for(ri i=1;i<=n;++i)sam.expend(calc(s[i]));
64         scanf("%s",s+1),n=strlen(s+1),sam.query();
65     }
66     return 0;
67 }


原文地址:https://www.cnblogs.com/zhangbuang/p/10886323.html

时间: 2024-07-31 03:42:02

poj3415 Common Substrings(后缀自动机)的相关文章

【POJ3415】Common Substrings 后缀自动机

转载请注明出处:http://blog.csdn.net/vmurder/article/details/42710069 其实我就是觉得原创的访问量比未授权盗版多有点不爽233... 题意: 给两个串,问有多少长度大于等于K的公共子串(位置不同也算一对) 题解: 后缀自动机DP 对第一个串建立后缀自动机,然后做一些预处理, 然后拿第二个串在后缀自动机上跑,到每个节点加一次贡献. 但是这样需要每个点往parent树上跑一遍,会TLE,所以可以加个lazy. 然后代码中有两次运用到拓扑序来从子向父

POJ3415:Common Substrings(后缀数组+单调栈)

Description 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| f

poj3415 Common Substrings(后缀数组,单调栈)

Common Substrings Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 8748 Accepted: 2899 Description 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

spoj 1811 LCS - Longest Common Substring (后缀自动机)

spoj 1811 LCS - Longest Common Substring 题意: 给出两个串S, T, 求最长公共子串. 限制: |S|, |T| <= 1e5 思路: dp O(n^2) 铁定超时 后缀数组 O(nlog(n)) 在spoj上没试过,感觉也会被卡掉 后缀自动机 O(n) 我们考虑用SAM读入字符串B; 令当前状态为s,同时最大匹配长度为len; 我们读入字符x.如果s有标号为x的边,那么s=trans(s,x),len = len+1; 否则我们找到s的第一个祖先a,它

POJ 3415 Common Substrings(后缀数组求重复字串)

题目大意:给你两个字符串,让你求出来两个字符串之间的重复子串长度大于k的有多少个. 解题思路: 先说论文上给的解释:基本思路是计算A的所有后缀和B的所有后缀之间的最长公共前缀的长度,把最长公共前缀长度不小于k的部分全部加起来.先将两个字符串连起来,中间用一个没有出现过的字符隔开.按height值分组后,接下来的工作便是快速的统计每组中后缀之间的最长公共前缀之和.扫描一遍,每遇到一个B的后缀就统计与前面的A的后缀能产生多少个长度不小于k的公共子串,这里A的后缀需要用一个单调的栈来高效的维护.然后对

poj Common Substrings(后缀数组&amp;单调队列)

Common Substrings Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 7082   Accepted: 2355 Description 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

【CF316G3】Good Substrings 后缀自动机

[CF316G3]Good Substrings 题意:给出n个限制(p,l,r),我们称一个字符串满足一个限制当且仅当这个字符串在p中的出现次数在[l,r]之间.现在想问你S的所有本质不同的子串中,有多少个满足所有限制. |S|,|p|<=10^5,n<=10. 题解:比较简单的后缀自动机题,我们先把原串和所有限制串放到一起建一个广义后缀自动机,然后在pre树上统计一下即可得到每个子串在每个限制串中出现了多少次.现在我们想知道原串中有多少满足条件的子串,即我们统计一下所有出现次数符合要求的,

POJ 3415 Common Substrings 后缀数组+并查集

后缀数组,看到网上很多题解都是单调栈,这里提供一个不是单调栈的做法, 首先将两个串 连接起来求height   求完之后按height值从大往小合并.  height值代表的是  sa[i]和sa[i-1] 的公共前缀长度,那么每次合并就是合并  i和i-1 那么在合并小的时候公共前缀更大的肯定已经都合并在一起,那么就可以直接统计了. #include<iostream> #include<cstdio> #include<algorithm> #include<

POJ - 3415 Common Substrings(后缀数组求长度不小于 k 的公共子串的个数+单调栈优化)

Description 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 val