[HNOI2004]L语言
emm。。。这东西的名字好像好多啊。。。而且有多重搞法。。。
但是比较正常的写法空间复杂度要小于其他的,时间都差不多。。。
首先,什么事前缀树
一种多路树形结构,常用来操作字符串(但不限于字符串)
性质:不同字符串的相同前缀只保留一份。。。
操作:插入、查找、删除。。。
举个 栗子
假使我们有这样一些单词需要存入
那么最后会存成这个样子:
注意:根节点应该是个空节点。。。
意会一下之后就可以来看一道简单的模板题了
对于这道题我们可以发现这是。。。基本操作。。。
所以这里就不在赘述了。。。直接上代码好了。。。
至于如何存储和查找看看代码应该也就理解了。。。
呆码:
#include<iostream> #include<cstdio> #include<cstring> #define jj k+ch[i]-'a' using namespace std; char ch[1000010]; int hash=26,l,n,m,w[30000010]; bool v[30000010],use[3000010]; inline void putin() { int k=0; for(int i=0;i<=l-1;i++) { if(!w[jj]) w[jj]=hash,hash+=26; k=w[jj]; if(i==l-1) v[k]=1; } } inline void find(int x) { int k=0; for(int i=x;i<=l-1;i++) { if(!w[jj]) return; k=w[jj]; if(v[k]) use[i]=1; } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%s",ch); l=strlen(ch); putin(); } for(int i=1;i<=m;i++) { int ans=0; memset(use,0,sizeof(use)); scanf("%s",ch); l=strlen(ch); find(ans); for(int j=0;j<=l-1;j++) if(use[j]) { ans=j+1; find(ans); } printf("%d\n",ans); } }
呆码:
#include<iostream> #include<cstdio> #include<cstring> #define maxn 20*10+10 #define MAXN 1024*1024+10 using namespace std; char ch[MAXN]; int n,m,rt=1,cnt=1,trie[maxn][26]; bool use[MAXN],mark[maxn]; inline void insert(int &x,int now,int l) { if(!x) x=++cnt; if(now==l) mark[x]=1; else insert(trie[x][ch[now]-'a'],now+1,l); } inline void find(int x,int now,int l) { if(mark[x] && x) use[now]=1; if(!x || now==l) return; find(trie[x][ch[now]-'a'],now+1,l); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%s",ch); int l=strlen(ch); insert(rt,0,l); } for(int i=1;i<=m;i++) { scanf("%s",ch); int l=strlen(ch); int ans=0; memset(use,0,sizeof(use)); use[0]=1; for(int j=0;j<=l;j++) if(use[j]) { find(rt,j,l); ans=j; } printf("%d\n",ans); } }