spoj 1812 lcsII (后缀自动机)

题意:求多个串的lcs,最多10个串,每个串最长10w

解题思路:后缀自动机。先建好第一个串的sam,然后后面的串拿上去跑(这个过程同前一题)。sam上,节点要记录两个信息,先说mi[p],其意思是p节点能匹配的所有串的最短的长度是多少,那我们如何更新这个mi呢?于是我们要记录另一个信息,mm[p]表示,跑当前串时,所跑到的节点能匹配的最大值,用这个最大值去更新mi。一个串跑完之后,要根据parent树,把mm往fa更新,然后用底下传上来的mm更新mi。怎么更新parent呢?很简单,我们知道,parent tree中父亲的代表串的长度必然比儿子短,所以我们只要根据代表串的长度排序,然后从后往前更新即可。

这题我有个小疑问,我们给mi赋初值时,用INF为何不可?而要用当前节点的val值呢?还望有知道的大神能不吝赐教啊。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std ; const int maxn = 311111 ; int max ( int a , int b ) { return a > b ? a : b ; }
int min ( int a , int b ) { return a < b ? a : b ; }
int wv[maxn<<1] , ws[maxn<<1] ;
int mm[maxn<<1] , mi[maxn<<1] ;
struct sam {
int fa[maxn<<1] , c[26][maxn<<1] , val[maxn<<1] , pos[maxn<<1] ;
int tot , last ;
inline int new_node ( int step ) {
val[++tot] = step ;
int i ;
for ( i = 0 ; i < 26 ; i ++ ) c[i][tot] = 0 ;
fa[tot] = 0 , mi[tot] = val[tot] ;
return tot ;
}
void add ( int k ) {
int p = last , i ;
int np = new_node ( val[p] + 1 ) ;
while ( p && !c[k][p] ) c[k][p] = np , p = fa[p] ;
if ( !p ) fa[np] = 1 ;
else {
int q = c[k][p] ;
if ( val[p] + 1 == val[q] ) fa[np] = q ;
else {
int nq = new_node ( val[p] + 1 ) ;
for ( i = 0 ; i < 26 ; i ++ ) c[i][nq] = c[i][q] ;
fa[nq] = fa[q] ;
fa[q] = fa[np] = nq ;
while ( p && c[k][p] == q ) c[k][p] = nq , p = fa[p] ;
}
}
last = np ;
}
void build ( char *s ) {
tot = 0 ;
last = new_node ( 0 ) ;
int len = strlen ( s ) , i ;
for ( i = 0 ; i < len ; i ++ ) add ( s[i] - 'a' ) ;
for ( i = 1 ; i <= tot ; i ++ ) wv[val[i]] ++ ;
for ( i = 1 ; i <= tot ; i ++ ) wv[i] += wv[i-1] ;
for ( i = 1 ; i <= tot ; i ++ ) ws[wv[val[i]]--] = i ;
}
void work ( char *s ) {
int len = strlen ( s ) ;
int p = 1 , i , temp = 0 ;
for ( i = 0 ; i < len ; i ++ ) {
int k = s[i] - 'a' ;
if ( c[k][p] ) temp ++ , p = c[k][p] ;
else {
while ( p && !c[k][p] ) p = fa[p] ;
if ( !p ) temp = 0 , p = 1 ;
else temp = val[p] + 1 , p = c[k][p] ;
}
mm[p] = max ( mm[p] , temp ) ;
}
for ( i = tot ; i >= 1 ; i -- ) {
p = ws[i] ;
mi[p] = min ( mi[p] , mm[p] ) ;
if ( fa[p] && mm[fa[p]] < mm[p] ) mm[fa[p]] = mm[p] ;
mm[p] = 0 ;
}
}
int solve () {
int i , ans = 0 ;
for ( i = 1 ; i <= tot ; i ++ )
ans = max ( ans , mi[i]) ;
return ans ;
}
} suf ;
char s[maxn] ;
int main () {
// freopen ( "a.txt" , "r" , stdin ) ;
scanf ( "%s" , s ) ;
suf.build ( s ) ;
int cnt = 0 ;
while ( scanf ( "%s" , s ) != EOF ) {
suf.work ( s ) ;
// cnt ++ ;
// if ( cnt == 2 ) break ;
}
printf ( "%d\n" , suf.solve () ) ;
}
/*
skds
fkds
aajfaa
*/

spoj 1812 lcsII (后缀自动机)的更多相关文章

  1. SPOJ.1812.LCS2(后缀自动机)

    题目链接 \(Description\) 求最多10个串的LCS(最长公共子序列). \(Solution\) 类比上题,对一个串建SAM,我们可以逐串地求出其在每个节点所能匹配的最大长度mx[i]. ...

  2. SPOJ 1812 LCS2 [后缀自动机 DP]

    题意: 求多个串<=10的最长连续子串 一个串建SAM,然后其他串在上面走 每个状态记录所有串在这个状态的公共子串的最小值 一个串在上面走的时候记录与每个状态公共子串的最大值,注意出现次数向父亲 ...

  3. POJ.2774.Long Long Message/SPOJ.1811.LCS(后缀自动机)

    题目链接 POJ2774 SPOJ1811 LCS - Longest Common Substring 确实比后缀数组快多了(废话→_→). \(Description\) 求两个字符串最长公共子串 ...

  4. SPOJ NSUBSTR Substrings 后缀自动机

    人生第一道后缀自动机,总是值得纪念的嘛.. 后缀自动机学了很久很久,先是看CJL的论文,看懂了很多概念,关于right集,关于pre,关于自动机的术语,关于为什么它是线性的结点,线性的连边.许多铺垫的 ...

  5. 2018.12.15 spoj Substrings(后缀自动机)

    传送门 后缀自动机基础题. 求长度为iii的子串出现次数的最大值. 对原串建出samsamsam,然后用sizsizsiz更新每个maxlenmaxlenmaxlen的答案. 然后由于后缀链接将其转化 ...

  6. SPOJ NSUBSTR Substrings ——后缀自动机

    建后缀自动机 然后统计次数,只需要算出right集合的大小即可, 然后更新f[l[i]]和rit[i]取个max 然后根据rit集合短的一定包含长的的性质,从后往前更新一遍即可 #include &l ...

  7. Lexicographical Substring Search SPOJ - SUBLEX (后缀自动机)

    Lexicographical Substrings Search \[ Time Limit: 149 ms \quad Memory Limit: 1572864 kB \] 题意 给出一个字符串 ...

  8. Substrings SPOJ - NSUBSTR (后缀自动机)

    Substrings \[ Time Limit: 100ms\quad Memory Limit: 1572864 kB \] 题意 给出一个长度为 \(250000\) 的字符串,求出所有 \(x ...

  9. Longest Common Substring II SPOJ - LCS2 (后缀自动机)

    Longest Common Substring II \[ Time Limit: 236ms\quad Memory Limit: 1572864 kB \] 题意 给出\(n\)个子串,要求这\ ...

随机推荐

  1. ubuntu中彻底删除nginx

    1.先执行一下命令: 1.1 删除nginx,–purge包括配置文件 sudo apt-get --purge remove nginx 1.2 自动移除全部不使用的软件包 sudo apt-get ...

  2. linq 总结

    linq 常用方法: top   var query=(from u in User ...).Take(10) dblinq的坑: 时间必须当参数传入,否则会报错 多个left join时,如果jo ...

  3. Qt+SQLite数据加密的一种思路(内存数据库)

    了解Qt是比较早的,可是一直没有耐心去做一个练习.近期花了差不多两周时间做了次Qt开发练习,基本完成了Qt的入门,逃脱微软平台又迈出了几小步.Qt虽然是C++的,但开发应用是比较方便的,我觉得它在界面 ...

  4. Web调试利器fiddler使用

    fiddler官网:http://fiddler2.com/ http://wenku.baidu.com/view/053e79d776a20029bd642dc1 http://www.cnblo ...

  5. Memcached初体验及原理解说

    1.简单介绍 Memcached 是一个 高性能的 分布式 内存对象缓存系统,用于动态Web应用降低数据库负载,提升性能. 2.试用场景 1.变化频繁,具有不稳定性的数据 (比方用户在线状态.在线人数 ...

  6. socket.io+angular.js+express.js做个聊天应用(四)

    接着上一篇 使用angularjs构建聊天室的client <!doctype html> <html ng-app="justChatting"> < ...

  7. Remoting简单实践

    一句话概括 remoting是微软的一种实现在不同的.net应用程序中进行分布式通信的技术 重要概念 原理大致是首先客户端通过remoting通道来获取服务器对象代理,通过序列化与反序列方式实现数据交 ...

  8. hdu2629Identity Card

    Problem Description Do you own an ID card?You must have a identity card number in your family's Hous ...

  9. Android:ServiceDemo

    效果图: layout的main.xml: <?xml version="1.0" encoding="utf-8"?> <LinearLay ...

  10. 浙江大学2015年校赛B题 ZOJ 3861 Valid Pattern Lock

    这道题目是队友写的,貌似是用暴力枚举出来. 题意:给出一组数,要求这组数在解锁的界面可能的滑动序列. 思路:按照是否能够直接到达建图,如1可以直接到2,但是1不能直接到3,因为中间必须经过一个2. 要 ...