[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 } 
时间: 2024-11-26 13:08:02

[POI2000]Repetitions的相关文章

【BZOJ】【2938】【POI2000】病毒

AC自动机 好题>_<(其实是一次AC有些感动) 嗯要找到无限长的一个字符串不包含任何一个模板串,就意味着在AC自动机(Trie图)上找到一个不经过任何一个危险结点的环,深搜一下就好了……记得离开某个结点的时候要清除标记!有点像tarjan…… 1 /************************************************************** 2 Problem: 2938 3 User: Tunix 4 Language: C++ 5 Result: Acce

[bzoj 2938] [Poi2000]病毒]

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2938 [Poi2000]病毒 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 870  Solved: 447[Submit][Status][Discuss] Description 二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码.如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的.现在委员会已经找出

【BZOJ】【2946】【POI2000】公共串

后缀数组 好感动,复习了下后缀数组居然写出来了……(感谢ykz大神) 求最长公共子串……WA了一发是因为:[不同字符串之间要用不同的特殊字符隔开]否则就会匹配到相同→_→比如都是aaa结尾,如果用相同特殊字符就会使得最长公共子串变成aaa#这样子…… 1 /************************************************************** 2 Problem: 2946 3 User: Tunix 4 Language: C++ 5 Result: Ac

【bzoj2947】[Poi2000]促销

2947: [Poi2000]促销 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 181  Solved: 120[Submit][Status][Discuss] Description Bytelandish连锁超市委托你编写一个程序来模拟一项即将施行的促销活动,该活动的规则如下: ●想要参与的顾客,只需把他的个人资料写在帐单上,并把帐单放入投票箱: ●每天活动结束时,数额最大.最小的两张帐单被取出,付款数额最大的顾客将获得一笔奖金,价值为取

BZOJ2947: [Poi2000]促销

2947: [Poi2000]促销 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 58  Solved: 33[Submit][Status] Description Bytelandish连锁超市委托你编写一个程序来模拟一项即将施行的促销活动,该活动的规则如下: ●想要参与的顾客,只需把他的个人资料写在帐单上,并把帐单放入投票箱: ●每天活动结束时,数额最大.最小的两张帐单被取出,付款数额最大的顾客将获得一笔奖金,价值为取出的两张帐单的数额之差

【POI2000】【BZOJ2946】公共串

2946: [Poi2000]公共串 Time Limit: 3 Sec Memory Limit: 128 MB Submit: 286 Solved: 121 [Submit][Status][Discuss] Description 给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 任务: l 读入单词 l 计算最长公共子串的长度 l 输出结果 Input 文件的第一行是整数 n,1<=n<=5,表示单词的数量.接下来n行每行一个单词,只由小写字母组成,单词的长度至少为1,最大

COGS 244. [POI2000] 滑雪队

244. [POI2000] 滑雪队 一个滑雪队在Byte山上组织了一次训练.山的北坡有一个滑雪场,所有的滑雪者都要从山上的起点站滑到山下的终点站.此次训练中各队员同时出发到终点站会合,除了始末两处外,队员们的滑雪路径不能相交,且山上的滑雪道只能从上往下滑. 滑雪道的分布地图由多块被林地连接的空地组成,每块空地都处于不同的高度.两块空地间至多由一块林地连接.滑雪过程中,滑雪者可以选择路径访问任一空地(但不必全部经过).各滑雪道只在空地相会,既不穿隧道,也不临空飞越. 任务: 编写一个程序完成下列

[BZOJ2946][Poi2000]公共串 后缀自动机

2946: [Poi2000]公共串 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 1367  Solved: 612[Submit][Status][Discuss] Description 给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 任务: l        读入单词 l        计算最长公共子串的长度 l        输出结果 Input 文件的第一行是整数 n,1<=n<=5,表示单词的数量.接下来n行每行一个单词

病毒[POI2000](AC自动机+搜索)

题目链接:病毒[POI2000] 我们假设已经有一个无限长的串满足要求,那如果我们拿它去匹配会发生什么? 它会一直在Trie树和fail树上转圈,一定经过根节点且不会经过病毒字符串结束的节点. 所以如果我们能找到一个环满足“一定经过根节点且不会经过病毒字符串结束的节点”,那么就可以找到一个无限长的串. 我们可以用dfs找环. #include <iostream> #include <cstdio> #include <cstring> #include <que