[POI2000]Repetitions

题目大意:
  求多个字符串的LCS。

思路:
  同SPOJ-LCS2,不过因为SPOJ上数据比较水,当时用错误的写法过掉了,这次用正确的写法重新过了一遍。
  拓扑排序按照每个状态的len值,用计数排序实现。
  每个状态往上更新时,应该对std::min(s[p].maxlen,s[q].len)取max(每个状态能匹配的最长子串长度不超过len)。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 const int inf=0x7fffffff;
  5 const int LEN=2001;
  6 int n;
  7 char s[LEN];
  8 class SuffixAutomaton {
  9     private:
 10         static const int SIGMA_SIZE=26;
 11         struct State {
 12             int len,link,go[SIGMA_SIZE],maxlen,min;
 13         };
 14         int sz,root,last,len;
 15         int cnt[LEN],top[LEN<<1];
 16         State s[LEN<<1];
 17         int newState(const int l) {
 18             sz++;
 19             s[sz].len=l;
 20             s[sz].min=inf;
 21             return sz;
 22         }
 23         int idx(const char ch) {
 24             return ch-'a';
 25         }
 26         void extend(const char ch) {
 27             int w=idx(ch);
 28             int p=last;
 29             int new_p=newState(s[p].len+1);
 30             while(p&&!s[p].go[w]) {
 31                 s[p].go[w]=new_p;
 32                 p=s[p].link;
 33             }
 34             if(!p) {
 35                 s[new_p].link=root;
 36                 s[root].go[w]=new_p;
 37             } else {
 38                 int q=s[p].go[w];
 39                 if(s[q].len==s[p].len+1) {
 40                     s[new_p].link=q;
 41                 } else {
 42                     int new_q=newState(s[p].len+1);
 43                     memcpy(s[new_q].go,s[q].go,sizeof s[q].go);
 44                     s[new_q].link=s[q].link;
 45                     s[q].link=s[new_p].link=new_q;
 46                     while(p&&s[p].go[w]==q) {
 47                         s[p].go[w]=new_q;
 48                         p=s[p].link;
 49                     }
 50                 }
 51             }
 52             last=new_p;
 53         }
 54     public:
 55         void build(char str[]) {
 56             root=last=newState(0);
 57             len=strlen(str);
 58             for(int i=0;str[i];i++) extend(str[i]);
 59         }
 60         void top_sort() {
 61             for(int i=1;i<=sz;i++) cnt[s[i].len]++;
 62             for(int i=len;i;i--) cnt[i-1]+=cnt[i];
 63             for(int i=1;i<=sz;i++) top[cnt[s[i].len]--]=i;
 64         }
 65         void match(char str[]) {
 66             int p=root,tmp=0;
 67             for(int i=0;str[i];i++) {
 68                 int w=idx(str[i]);
 69                 if(s[p].go[w]) {
 70                     tmp++;
 71                     p=s[p].go[w];
 72                 } else {
 73                     while(p&&!s[p].go[w]) {
 74                         p=s[p].link;
 75                     }
 76                     if(!p) {
 77                         tmp=0;
 78                         p=root;
 79                     } else {
 80                         tmp=s[p].len+1;
 81                         p=s[p].go[w];
 82                     }
 83                 }
 84                 s[p].maxlen=std::max(s[p].maxlen,tmp);
 85             }
 86             for(int i=1;i<=sz;i++) {
 87                 int p=top[i],q=s[p].link;
 88                 s[q].maxlen=std::max(s[q].maxlen,std::min(s[p].maxlen,s[q].len));
 89                 s[p].min=std::min(s[p].min,s[p].maxlen);
 90                 s[p].maxlen=0;
 91             }
 92         }
 93         int lcs() {
 94             int ret=0;
 95             for(int i=1;i<=sz;i++) ret=std::max(ret,s[i].min);
 96             return ret;
 97         }
 98 };
 99 SuffixAutomaton sam;
100 int main() {
101     scanf("%d",&n);
102     scanf("%s",s);
103     sam.build(s);
104     sam.top_sort();
105     for(int i=2;i<=n;i++) {
106         scanf("%s",s);
107         sam.match(s);
108     }
109     printf("%d\n",sam.lcs());
110     return 0;
111 } 

 

posted @ 2017-09-14 11:27  skylee03  阅读(141)  评论(0编辑  收藏  举报