最长前缀
Description
一些生物体的复杂结构可以用其基元的序列表示,而一个基元用一个大写英文字符串表示。
生物学家的一个问题就是一个这样的长序列分解为基元(字符串)的序列。对于给定的基元集合
P
,如果可以从中选出
在从
例如,序列
ABABACABAAB
可以由基元集合{
A,AB,BA,CA,BBC
} 构成。
字符串的前
K
个字符为该字符串的前缀,其长度为
请写一个程序,对于输入的基元集合
P
和字符串
Input
第一行是基元集合
P
中的基元数目
随后一行是一个长度为
L
的大写英文字符串,表示该基元。
每个基元互不相同。
最后一行描述要处理的字符串
Output
只有一行,一个数字,表示可以由
P
构成的
Sample Input
5
1
A
2
AB
3
BBC
2
CA
2
BA
ABABACABAABCB.
Sample Output
11
Solution
设
fi
表示前
i−1
个字符能否被基元表示出来。
则对于
fi−1=true
,都查找第
i
位开始是否能由前缀构成。
这个过程可以用
Code
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
struct Node{
int nxt[27];
bool end;
Node(){
memset(nxt,-1,sizeof nxt);
end=false;
}
}Trie[100010];
int n,top=1;
char s[50];
char t[500010];
bool f[500010];
void push(int len){
int now=1;
for(int i=0;i<len;i++){
if(Trie[now].nxt[s[i]-'0']!=-1)now=Trie[now].nxt[s[i]-'0'];
else{
Trie[now].nxt[s[i]-'0']=++top;
now=top;
}
}
Trie[now].end=true;
}
void find(char *str,int len,int start){
int now=1,i;
for(i=0;i<len;i++){
if(Trie[now].nxt[str[i]-'0']!=-1)now=Trie[now].nxt[str[i]-'0'];
else break;
if(Trie[now].end)f[start+i]=true;
}
}
int main(){
freopen("prefix.in","r",stdin);
freopen("prefix.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++){
int l;
scanf("%d%s",&l,s);
push(l);
}
scanf("%s",t);
int rl=strlen(t),i;
rl--;
for(i=0;i<rl;i++){
if(i==0||f[i-1])find(t+i,rl-i,i);
}
for(i=rl-1;i>=0;i--)if(f[i]){
printf("%d\n",i+1);
return 0;
}
return 0;
}