2.3.1 Longest Prefix 最长前缀(字典树)

Description

在生物学中,一些生物的结构是用包含其要素的大写字母序列来表示的。生物学家对于把长的序列分解成较短的(称之为元素的)序列很感兴趣。 如果一个集合 P 中的元素可以通过串联(允许重复;串联,相当于 Pascal 中的 “+” 运算符)组成一个序列 S ,那么我们认为序列 S 可以分解为 P 中的元素。并不是所有的元素都必须出现。举个例子,序列 ABABACABAAB 可以分解为下面集合中的元素: {A, AB, BA, CA, BBC} 序列 S 的前面 K 个字符称作 S 中长度为 K 的前缀。设计一个程序,输入一个元素集合以及一个大写字母序列,计算这个序列最长的前缀的长度。

Input

输入数据的开头包括 1..200 个元素(长度为 1..10 )组成的集合,用连续的以空格分开的字符串表示。字母全部是大写,数据可能不止一行。元素集合结束的标志是一个只包含一个 “.” 的行。集合中的元素没有重复。接着是大写字母序列 S ,长度为 1..200,000 ,用一行或者多行的字符串来表示,每行不超过 76 个字符。换行符并不是序列 S 的一部分。

Output

只有一行,输出一个整数,表示 S 能够分解成 P 中元素的最长前缀的长度。

Sample Input

A AB BA CA BBC

ABABACABAABC

Sample Output

11

 

 

题意也是不好理解啊。。。

意思就是:从第一个集合里,选任意个元素组成一个字符串,这些元素可以重复,也可以不选。问组成的这样的字符串在第二个串里的最长前缀是多少!


按照输入的单词构造字典树,并且在每一个单词的末尾节点标记。

对给定的模式串在字典树上进行查找。

查找的过程是这样的,从第一个字母遍历到最后一个字母,每一次都做一次(从当前下标 i 到字符串末尾)的查找(或者说是匹配)。设一个新的数组 is[ i ] 代表当前下标之前的子串能否满足题目的最长前缀。

那么如果is[i]==true,就代表 i 之前的子串一定满足题目条件的最长前缀。

模拟一下过程:

现命名第二个串为模式串,第一个串里的单词为元素。

从下标0开始,发现元素A和AB在模式串里,那么标记 is[0]和is[1],代表暂时能够组合成ABA这个前缀,以此类推。

到了下标5的时候,发现is[4] 为1,那么继续匹配,标记is[6],但此时is[5]是不标记的,因为ABABAC这个串是组合不了的,但是ABABACA又能组合,所以标记is[6]......

通过上述过程我们可以发现,只要is[i-1]被标记,那么就可以去字典树上做一遍匹配。

最后找到最后一个is[i]=1的下标输出i+1即可。


(还是比较裸的字典树

此题还有很多种解法,dp,记忆化搜索,ac自动机。这儿就不写了(我可能不会写- -!),因为师弟问,才做了这道题- -。

 

小插曲:一开始T了,后来发现是一开始因为字符串的长度我每次都写的strlen(str),后来改掉就过了2333


#include
#include
#include
#include
#include
#include
#define memset(a,v)  memset(a,v,sizeof(a))
#define max(a,b)   (a>b?a:b)
#define min(a,b)   (a=0;i--)
        if(is[i]==true){
            ans=i+1;break;
        }
    cout<

 

你可能感兴趣的:(USACO)