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<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#define memset(a,v) memset(a,v,sizeof(a))
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define swap(a,b) (a=a+b,b=a-b,a=a-b)
#define eps 1.0E-8
using namespace std;
const int MAXL(2*1e5);
const int INF(0x7f7f7f7f);
const int mod(1e9+7);
typedef long long int LL;
int trie[MAXL+50][30];
bool ed[MAXL+50];
bool is[MAXL+50];
char word[12];
char str[MAXL+50];
char s[80];
int tot,len;
void buildTree()
{
int root=0;
for(int i=0;i<strlen(word);i++)
{
int id=word[i]-'A';
if(!trie[root][id])
trie[root][id]=++tot;
root=trie[root][id];
}
ed[root]=true;
}
void wordSearch(int k)
{
int root=0;
for(int i=k;i<len;i++)
{
int id=str[i]-'A';
if(!trie[root][id])
return;
root=trie[root][id];
if(ed[root]==true)
is[i]=true;
}
}
int main()
{
while(scanf("%s",word))
{
if(word[0]=='.') break;
buildTree();
}
while(~scanf("%s",s))
strcat(str,s);
len=strlen(str);
wordSearch(0);
for(int i=1;i<len;i++)
if(is[i-1]==true)
wordSearch(i);
int ans=0;
/*
for(int i=0;i<len;i++)
cout<<is[i]<<" ";
cout<<endl;
*/
for(int i=len-1;i>=0;i--)
if(is[i]==true){
ans=i+1;break;
}
cout<<ans<<endl;
}
/*
A AB BA CA BBC
.
ABABACABAABC
*/