题目描述
标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的。现在你要处理的就是一段没有标点的文章。
一段文章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下能够被理解的最长前缀的位置。
输入输出格式
输入格式:输入文件第一行是两个正整数n和m,表示字典D中有n个单词,且有m段文章需要被处理。之后的n行每行描述一个单词,再之后的m行每行描述一段文章。
其中1<=n, m<=20,每个单词长度不超过10,每段文章长度不超过1M。
输出格式:对于输入的每一段文章,你需要输出这段文章在字典D可以被理解的最长前缀的位置。
输入输出样例
题解
为什么AC自动机没什么近乎模板的题写啊QAQ
在上古年代写过一个Trie+爆搜的代码↓

1 /* 2 qwerta 3 P2292 [HNOI2004]L语言 4 Accepted 5 100 6 代码 C++,1.01KB 7 提交时间 2018-05-19 16:28:10 8 耗时/内存 9 832ms, 6812KB 10 */ 11 #include<cstdio> 12 #include<cstring> 13 #include<iostream> 14 using namespace std; 15 struct emm{ 16 int z[27]; 17 bool en; 18 }a[2500007]; 19 char s[1000007]; 20 int f[1000007]; 21 int t=0; 22 void build() 23 { 24 int d=strlen(s)-1; 25 int e=0; 26 while(d>=0) 27 { 28 if(a[e].z[s[d]-96])e=a[e].z[s[d]-96]; 29 else e=a[e].z[s[d]-96]=++t; 30 d--; 31 } 32 a[e].en=true; 33 return; 34 } 35 int ans=0; 36 void search(int c) 37 { 38 int e=0,d=c-1; 39 while(d>=0&&a[e].z[s[d]-96]) 40 { 41 //cout<<c<<" "; 42 e=a[e].z[s[d]-96]; 43 if(a[e].en) 44 { 45 if(f[d]||d==0) 46 {f[c]=1;ans=c;return;} 47 } 48 d--; 49 } 50 return; 51 } 52 int main() 53 { 54 //freopen("a.in","r",stdin); 55 int n,m; 56 cin>>n>>m; 57 for(int i=1;i<=n;++i) 58 { 59 cin>>s; 60 build(); 61 } 62 for(int i=1;i<=m;++i) 63 { 64 ans=0; 65 cin>>s; 66 int len=strlen(s); 67 memset(f,0,sizeof(f)); 68 f[0]=1; 69 for(int j=1;j<=len;++j) 70 search(j); 71 cout<<ans<<endl; 72 } 73 return 0; 74 }
感觉自己现在写不出这种上古绝学了QAQ(逃
用AC自动机把单词出现的位置跑出来,转换成区间
问题转换成选择不重合的区间从0开始覆盖,最远的覆盖到哪儿。
然后写一个BFS跑一下就行了。
BFS:首先把0push进队列,然后跑以0为左端点的区间,每次把右端点push进去。
加上判重之后可以$O(L)$。
居然比上古绝学慢了三百毫秒QAQ
1 /* 2 qwerta 3 P2292 [HNOI2004]L语言 4 Accepted 5 100 6 代码 C++,2.53KB 7 提交时间 2018-10-08 08:42:03 8 耗时/内存 9 1121ms, 28908KB 10 */ 11 #include<algorithm> 12 #include<iostream> 13 #include<cstring> 14 #include<cstdio> 15 #include<queue> 16 #include<cmath> 17 using namespace std; 18 #define R register 19 struct emm{ 20 int fal; 21 int nxt[26]; 22 int tag,l; 23 }AC[203];//Tree结构体 24 queue<int>q; 25 struct ahh{ 26 int f,e; 27 }a[2000003];//用来区间覆盖 28 int h[2000003]; 29 bool sf[2000003];//判重 30 int main() 31 { 32 //freopen("a.in","r",stdin); 33 ios::sync_with_stdio(false); 34 cin.tie(false),cout.tie(false);//关闭同步流(卡常 35 int n,m; 36 cin>>n>>m; 37 int cnt=0; 38 //build_Trie 39 for(R int i=1;i<=n;++i) 40 { 41 string s; 42 cin>>s; 43 int len=s.length(); 44 int now=0; 45 for(R int j=0;j<len;++j) 46 { 47 if(!AC[now].nxt[s[j]-'a']) 48 AC[now].nxt[s[j]-'a']=++cnt; 49 now=AC[now].nxt[s[j]-'a']; 50 } 51 AC[now].tag=i; 52 AC[now].l=len;//记录这个区间的长度 53 } 54 //get_fail 55 { 56 for(R int i=0;i<26;++i) 57 if(AC[0].nxt[i]) 58 { 59 AC[AC[0].nxt[i]].fal=0; 60 q.push(AC[0].nxt[i]); 61 } 62 while(!q.empty()) 63 { 64 int x=q.front();q.pop(); 65 for(R int i=0;i<26;++i) 66 { 67 if(AC[x].nxt[i]) 68 { 69 AC[AC[x].nxt[i]].fal=AC[AC[x].fal].nxt[i]; 70 q.push(AC[x].nxt[i]); 71 } 72 else 73 AC[x].nxt[i]=AC[AC[x].fal].nxt[i]; 74 } 75 } 76 } 77 //runAC 78 for(R int i=1;i<=m;++i) 79 { 80 //cout<<"i="<<i<<endl; 81 memset(a,0,sizeof(a)); 82 memset(h,0,sizeof(h)); 83 int tot=0; 84 string t; 85 cin>>t; 86 int lent=t.length(); 87 int now=0; 88 for(R int j=0;j<lent;++j) 89 { 90 now=AC[now].nxt[t[j]-'a']; 91 for(R int k=now;k;k=AC[k].fal) 92 if(AC[k].tag) 93 { 94 //a[++tot].r=j; 95 //a[tot].l=j-AC[k].l+1; 96 int ll=j-AC[k].l+1;//这个区间的左端点=右端点-长度+1 97 a[++tot].f=h[ll];//邻接链表加边 98 h[ll]=tot; 99 a[tot].e=j; 100 } 101 } 102 //cout<<"get"<<endl; 103 //bfs 104 memset(sf,0,sizeof(sf)); 105 int ans=-1; 106 { 107 q.push(0); 108 while(!q.empty()) 109 { 110 int x=q.front();q.pop(); 111 //cout<<"x="<<x<<endl; 112 ans=max(ans,x-1); 113 for(R int i=h[x];i;i=a[i].f) 114 if(!sf[a[i].e])//判重 115 { 116 sf[a[i].e]=1; 117 q.push(a[i].e+1); 118 //cout<<"push "<<a[i].e+1<<endl; 119 } 120 } 121 } 122 cout<<ans+1<<endl; 123 } 124 return 0; 125 }