标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的。现在你要处理的就是一段没有标点的文章。 一段文章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下能够被理解的最长前缀的位置。
--byBZOJ
http://www.lydsy.com/JudgeOnline/problem.php?id=1212
算是AC-自动机?DP?
好吧也许不算;
她就是个Trie上的暴力么。。。
对文章的每个前缀f[i](长度为i)
f[i]合法,仅当存在:f[j](j<i)合法,且j+1到i为一个单词
然后,就对于每个i,枚举j(i-j>10):使f[j]合法,且j+1到i能被一个单词匹配
对了就是匹配,建个AC-自动机,因为连fail都不(能)用,所以也就是个trie树了,对j+1到i进行匹配就行了。
代码如下:
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 int m,n; 5 char s[21]; 6 char word[1050001]; 7 struct ss{ 8 int ch[27]; 9 }trie[1501]; 10 int tot,biggest,smallest; 11 int is_end[1501],fail[1501]; 12 int f[1050001]; 13 int que[10000]; 14 void bfs_fail(); 15 void compare(); 16 int main() 17 { 18 int i,j,k,len; 19 scanf("%d%d",&n,&m); 20 for(i=1;i<=n;i++){ 21 getchar(); 22 scanf("%s",s); 23 len=strlen(s)-1;k=0; 24 if(len>biggest)biggest=len; 25 if(len<smallest)smallest=len; 26 for(j=0;j<=len;j++){ 27 if(!trie[k].ch[s[j]-'a']) 28 trie[k].ch[s[j]-'a']=++tot; 29 k=trie[k].ch[s[j]-'a']; 30 } 31 is_end[k]=1; 32 } 33 for(i=1;i<=m;i++){ 34 getchar(); 35 scanf("%s",word); 36 compare(); 37 } 38 return 0; 39 } 40 void compare(){ 41 memset(f,0,sizeof(f)); 42 int i,j,tem1=0,tem2=0,ans=0,len=strlen(word)-1; 43 f[0]=1; 44 for(i=1;i<=len+1;i++){ 45 for(j=i-smallest+1;j>=0&&j>=i-biggest-1;j--) 46 if(f[j]){ 47 tem1=0;tem2=j; 48 while(tem2<=i-1){ 49 if(trie[tem1].ch[word[tem2]-'a']){ 50 tem1=trie[tem1].ch[word[tem2]-'a']; 51 tem2++; 52 } 53 else 54 break; 55 } 56 if(tem2==i&&is_end[tem1]){ 57 f[i]=1; 58 ans=i; 59 break; 60 } 61 } 62 } 63 printf("%d ",ans); 64 }
祝AC哟!