题目大意:
求两个字符串的LCS。
思路:
对其中一个字符串构建SAM,然后用另一个字符串在里面匹配,按照SAM的边一直往下走,匹配到的连续的字符数就是公共字串的长度。
1 #include<string> 2 #include<cstring> 3 #include<iostream> 4 std::string s,t; 5 class SuffixAutomaton { 6 private: 7 static const int SIGMA_SIZE=26; 8 int idx(const char ch) { 9 return ch-'a'; 10 } 11 struct State { 12 State *link,*go[SIGMA_SIZE]; 13 int len; 14 State(const int l) { 15 link=NULL; 16 len=l; 17 memset(go,0,sizeof go); 18 } 19 }; 20 State *root,*last; 21 void extend(const char ch) { 22 int w=idx(ch); 23 State *p=last; 24 State *new_p=new State(p->len+1); 25 while(p!=NULL&&p->go[w]==NULL) { 26 p->go[w]=new_p; 27 p=p->link; 28 } 29 if(p==NULL) { 30 new_p->link=root; 31 } else { 32 State *q=p->go[w]; 33 if(q->len==p->len+1) { 34 new_p->link=q; 35 } else { 36 State *new_q=new State(p->len+1); 37 memcpy(new_q->go,q->go,sizeof q->go); 38 new_q->link=q->link; 39 q->link=new_p->link=new_q; 40 while(p!=NULL&&p->go[w]==q) { 41 p->go[w]=new_q; 42 p=p->link; 43 } 44 } 45 } 46 last=new_p; 47 } 48 public: 49 void build(std::string &s) { 50 last=root=new State(0); 51 for(std::string::iterator i=s.begin();i<s.end();i++) extend(*i); 52 } 53 int match(std::string &s) { 54 int ret=0,tmp=0; 55 State *p=root; 56 for(std::string::iterator i=s.begin();i<s.end();i++) { 57 int w=idx(*i); 58 if(p!=NULL&&p->go[w]!=NULL) { 59 p=p->go[w]; 60 tmp++; 61 } else { 62 while(p!=NULL&&p->go[w]==NULL) p=p->link; 63 if(p==NULL) { 64 p=root; 65 tmp=0; 66 } else { 67 tmp=p->len+1; 68 p=p->go[w]; 69 } 70 } 71 ret=std::max(ret,tmp); 72 } 73 return ret; 74 } 75 }; 76 SuffixAutomaton sam; 77 int main() { 78 std::ios_base::sync_with_stdio(false); 79 std::cin.tie(NULL); 80 std::cin>>s; 81 sam.build(s); 82 std::cin>>s; 83 std::cout<<sam.match(s)<<std::endl; 84 return 0; 85 }