BZOJ-1212 [HNOI2004]L语言(trie+dp)
题目描述
一段文章 \(T\) 由若干小写字母构成,一个单词 \(W\) 也是由若干小写字母构成,一个字典 \(D\) 是若干个单词的集合。 我们称一段文章 \(T\) 在某个字典 \(D\) 下是可以被理解的,是指如果文章 \(T\) 可以被分成若干部分,且每一个部分都是字典 \(D\) 中的单词。 例如字典 \(D\) 中包括单词 {is,name,what,your},则文章 whatisyourname 是在字典 \(D\) 下可以被理解的。因为它可以分成 \(4\) 个单词:what,is,your,name,且每个单词都属于字典 \(D\),而文章 whatisyouname 在字典 \(D\) 下不能被理解,但可以在字典 D'=D+{you} 下被理解。这段文章的一个前缀 whatis,也可以在字典 \(D\) 下被理解,而且是在字典 \(D\) 下能够被理解的最长的前缀。 给定一个字典 \(D\),判断若干段文章在字典 \(D\) 下是否能够被理解。 并给出其在字典 \(D\) 下能够被理解的最长前缀的位置。
字典 \(D\) 中有 \(n\) 个单词,且有 \(m\) 段文章需要被处理,其中 \(1\leq n,m\leq 20\),每个单词长度不超过 \(10\),每段文章长度不超过 \(1MB\)。
分析
把 \(n\) 个单词插入 \(\text{trie}\),在每个单词的结尾字符进行标记,设 \(dp[i]\) 为文章的前 \(i\) 个字符能否在 \(\text{trie}\) 中匹配成功,能匹配成功为 \(1\),不能则为 \(0\)。文章在 \(\text{trie}\) 中匹配时,如果某个节点有单词的结尾标记,则更新 \(dp[j]=1\)。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e6+10;
char str[N];
int trie[2010][30],ed[2010],tot=1,dp[N];
void insert(char *str)
{
int p=1;
int len=strlen(str);
for(int i=0;i<len;i++)
{
int ch=str[i]-'a';
if(trie[p][ch]==0)
trie[p][ch]=++tot;
p=trie[p][ch];
}
ed[p]++;
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
scanf("%s",str);
insert(str);
}
while(m--)
{
scanf("%s",str+1);
int len=strlen(str+1),ans=0;
memset(dp,0,sizeof(dp));
dp[0]=1;
for(int i=0;i<=len;i++)
{
if(dp[i]==1)
{
ans=i;
int p=1;
for(int j=i+1;j<=len;j++)
{
int ch=str[j]-'a';
p=trie[p][ch];
if(p==0)
break;
if(ed[p]!=0)
dp[j]=1;
}
}
}
cout<<ans<<endl;
}
return 0;
}
posted on 2020-11-24 14:15 DestinHistoire 阅读(67) 评论(0) 收藏 举报
浙公网安备 33010602011771号