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
题意:
找出S,T两串中所有相同的长度大于等于K的字符串。不判重,即位置不同的相同串要重复统计。
解法:
- 已知,对于一个串S,后缀自动机可以得到其所有的子串,以及递推出不同字串出现的数量num。
- 对于匹配串T,一个字符一个字符的走一趟自动机(假设现在走到了T[i]),可以得到S中以T[i]结尾的集合,然后用集合中满足>=k的元素乘以num。
- 里面有拓扑关系,用了lazy标记。
- 加了输入优化,时间排名第三。
注意:
ans=ans+(long long)lazy[p]*(maxlen[p]-max(K,maxlen[slink[p]]+1)+1)*num[p];
开始把long long的位置写错了,wa了很多次。
错误位置:ans=(long long)ans+lazy[p]*(maxlen[p]-max(K,maxlen[slink[p]]+1)+1)*num[p];
(难道是先执行乘法,这个时候long long无效?)
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<memory> #include<algorithm> using namespace std; const int maxn=201000; int K;char chr[maxn]; struct SAM { int sz,Last,ch[maxn][52],slink[maxn],maxlen[maxn]; int c[maxn],pos[maxn],num[maxn],lazy[maxn]; //num表示一个模板串S中x集合出现的次数,lazy表示匹配串T中x集合的累加(向上slink(fa)传递)。 //pos是拓扑排序后的结果,用来递推num和lazy。 long long ans; int get(char x) { if(x>='a'&&x<='z') return x-'a'; return x-'A'+26; } void init() { sz=0; Last=sz=1; memset(ch[1],0,sizeof(ch[1])); num[1]=lazy[1]=0; } void add(int x) { int np=++sz,p=Last;Last=np; lazy[sz]=0;num[sz]=1; maxlen[np]=maxlen[p]+1; memset(ch[np],0,sizeof(ch[np])); while(p&&!ch[p][x]) ch[p][x]=np,p=slink[p]; if(!p) slink[np]=1; else { int q=ch[p][x]; if(maxlen[q]==maxlen[p]+1) slink[np]=q; else { int nq=++sz; lazy[sz]=num[sz]=0; memcpy(ch[nq],ch[q],sizeof(ch[q])); slink[nq]=slink[q],slink[np]=slink[q]=nq; maxlen[nq]=maxlen[p]+1; while(p&&ch[p][x]==q) ch[p][x]=nq,p=slink[p]; } } } void sort() { for(int i=0;i<=sz;i++) c[i]=0; for(int i=1;i<=sz;i++) c[maxlen[i]]++; for(int i=1;i<=sz;i++) c[i]+=c[i-1]; for(int i=1;i<=sz;i++) pos[c[maxlen[i]]--]=i; for(int i=sz;i>=1;i--) num[slink[pos[i]]]+=num[pos[i]]; } void solve() { char c=getchar(); while(!(c>='a'&&c<='z')&&!(c>='A'&&c<='Z')) c=getchar(); int mp=1,Len=0;ans=0; while((c>='a'&&c<='z')||(c>='A'&&c<='Z')) { int x=get(c);c=getchar(); if(ch[mp][x]){ Len++; mp=ch[mp][x];} else { while(mp&&!ch[mp][x]) mp=slink[mp]; if(!mp) { mp=1; Len=0; }//~ else { Len=maxlen[mp]+1; mp=ch[mp][x]; } } if(Len>=K) { ans=(long long)ans+(Len-max(maxlen[slink[mp]]+1,K)+1)*num[mp]; if(maxlen[slink[mp]]>=K) lazy[slink[mp]]++; } } for(int i=sz;i>=1;i--) { int p=pos[i]; ans=ans+(long long)lazy[p]*(maxlen[p]-max(K,maxlen[slink[p]]+1)+1)*num[p]; if(maxlen[slink[p]]>=K) lazy[slink[p]]+=lazy[p]; } printf("%lld ",ans); } }; SAM sam; int main() { while(~scanf("%d",&K)){ if(K==0) return 0; sam.init(); char c=getchar(); while(!(c>='a'&&c<='z')&&!(c>='A'&&c<='Z')) c=getchar(); while((c>='a'&&c<='z')||(c>='A'&&c<='Z')) sam.add(sam.get(c)),c=getchar(); sam.sort(); sam.solve(); } return 0; }