题目大意:给定一个字符串集合P和一个字符串S,问S可以由P集合内元素拼成的最长前缀长度。
KMP?不可能的。
一看这种题就是来一记大爆搜,设DFS(pos)表示搜到了S的第pos位,枚举下一个位置i,[pos,i]字串若在集合P中出现过则DFS(i+1),ans=max(ans,i)。
特别地,若pos位置被搜过,那后面的情况是一样的,return就可以了。
不想用map,打了一棵Trie,跑的比map还慢。
#include<iostream> #include<iomanip> #include<cstring> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; inline int read() { char ch; bool bj=0; while(!isdigit(ch=getchar())) bj|=(ch=='-'); int res=ch^(3<<4); while(isdigit(ch=getchar())) res=(res<<1)+(res<<3)+(ch^(3<<4)); return bj?-res:res; } void printnum(int x) { if(x>9)printnum(x/10); putchar(x%10+'0'); } inline void print(int x,char ch) { if(x<0) { putchar('-'); x=-x; } printnum(x); putchar(ch); } struct Trie { struct TriePoint { int ch[26],bj; } tree[100005]; int cnt; inline void Insert(string s) { int len=s.length(),x,root=0; for(int i=0; i<len; i++) { x=s[i]-'A'; if(!tree[root].ch[x])tree[root].ch[x]=++cnt; root=tree[root].ch[x]; } tree[root].bj=1; } inline bool Find(string s) { int len=s.length(),x,root=0; for(int i=0; i<len; i++) { x=s[i]-'A'; if(!tree[root].ch[x])return 0; root=tree[root].ch[x]; } return tree[root].bj; } } T; string s,S; int maxn,n,ans; bool vst[1200005],bj; void DFS(int pos) { if(vst[pos])return; vst[pos]=1; if(pos==n)return; string tmp=""; for(int i=pos; i<n; i++) { if(i-pos>=maxn)return; tmp+=S[i]; if(T.Find(tmp)) { bj=1; ans=max(ans,i); DFS(i+1); } } } signed main() { while(cin>>s&&s[0]!='.') { T.Insert(s); maxn=max(maxn,(int)s.length()); } S=""; while(cin>>s)S+=s; n=S.length(); DFS(0); if(!bj)puts("0"); else print(ans+1,' '); return 0; }
P.S.字符串是0开头的,ans最后要加一。