[SPOJ-LCS2]Longest Common Substring II
题目大意:
求若干个字符串的LCS。
思路:
对于第一个字符串构造SAM,然后把后面的字符串放在SAM中匹配,对于同一个字符串匹配到的同一个状态,记录其匹配长度之max,
然后对于不同的字符串匹配到的同一个状态,记录其匹配长度之min,然后对于所有的状态取max。
然而这样只能过9个点,第10个点会WA,原因是如果不同的字符串匹配到的同一个字串,可能并不在SAM的同一个状态上,
因此要将这些值与它的parent(程序中的link)共享(不需要往下传,否则会TLE,因为只要下面的往上传过,不管怎样都能在上面取到max)。
我们可以沿着link一直往上跳,同时更新,然后就TLE了。
考虑按照拓扑序(状态加入的SAM顺序)DP,对于每个状态,只要更新一次就可以,其余的状态都可以递推得到。
由于STL用得太多,常数巨大,跑了200ms,但还是勉强进了VJudge的Leaderboard(Rank50),Rank49都只有80ms。
关掉I/O同步以后也跑了180ms。
1 #include<string> 2 #include<vector> 3 #include<iostream> 4 const int inf=0x7fffffff; 5 std::string s; 6 class SuffixAutomaton { 7 private: 8 static const int SIGMA_SIZE=26,N=10; 9 struct State { 10 State *link,*go[SIGMA_SIZE]; 11 int len,maxlen[N]; 12 State(const int l) { 13 link=nullptr; 14 std::fill(&go[0],&go[SIGMA_SIZE],nullptr); 15 std::fill(&maxlen[0],&maxlen[N],0); 16 maxlen[0]=inf; 17 len=l; 18 } 19 }; 20 State *root,*last; 21 int idx(const int ch) { 22 return ch-'a'; 23 } 24 std::vector<State*> v; 25 void extend(const char ch) { 26 const int w=idx(ch); 27 State *p=last; 28 State *new_p=new State(p->len+1); 29 v.push_back(new_p); 30 while(p!=nullptr&&p->go[w]==nullptr) { 31 p->go[w]=new_p; 32 p=p->link; 33 } 34 if(p==nullptr) { 35 new_p->link=root; 36 } else { 37 State *q=p->go[w]; 38 if(q->len==p->len+1) { 39 new_p->link=q; 40 } else { 41 State *new_q=new State(p->len+1); 42 v.push_back(new_q); 43 std::copy(&q->go[0],&q->go[SIGMA_SIZE],new_q->go); 44 new_q->link=q->link; 45 new_p->link=q->link=new_q; 46 while(p!=nullptr&&p->go[w]==q) { 47 p->go[w]=new_q; 48 p=p->link; 49 } 50 } 51 } 52 last=new_p; 53 } 54 public: 55 int cnt; 56 void build(std::string &s) { 57 root=last=new State(0); 58 for(std::string::iterator i=s.begin();i<s.end();i++) extend(*i); 59 } 60 void match(std::string &s) { 61 cnt++; 62 State *p=root; 63 int tmp=0; 64 for(std::string::iterator i=s.begin();i<s.end();i++) { 65 const int w=idx(*i); 66 if(p->go[w]!=nullptr) { 67 p=p->go[w]; 68 tmp++; 69 } else { 70 while(p!=nullptr&&p->go[w]==nullptr) { 71 p=p->link; 72 } 73 if(p==nullptr) { 74 tmp=0; 75 p=root; 76 } else { 77 tmp=p->len+1; 78 p=p->go[w]; 79 } 80 } 81 p->maxlen[cnt]=std::max(p->maxlen[cnt],tmp); 82 } 83 for(std::vector<State*>::iterator i=v.begin();i!=v.end();i++) { 84 State *p=*i,*q=(*i)->link; 85 if(q!=nullptr&&q->maxlen[cnt]!=p->maxlen[cnt]) { 86 q->maxlen[cnt]=std::max(q->maxlen[cnt],std::min(p->maxlen[cnt],q->len)); 87 } 88 } 89 for(std::vector<State*>::iterator i=v.begin();i!=v.end();i++) { 90 State *p=*i; 91 p->maxlen[0]=std::min(p->maxlen[0],p->maxlen[cnt]); 92 } 93 } 94 int lcs() { 95 int ret=0; 96 for(std::vector<State*>::iterator i=v.begin();i!=v.end();i++) { 97 State *p=*i; 98 ret=std::max(ret,p->maxlen[0]); 99 } 100 return ret; 101 } 102 }; 103 SuffixAutomaton sam; 104 int main() { 105 std::ios_base::sync_with_stdio(false); 106 std::cin.tie(NULL); 107 std::cin>>s; 108 sam.build(s); 109 while(std::cin>>s) sam.match(s); 110 std::cout<<sam.lcs()<<std::endl; 111 return 0; 112 }