题目:
思路:trie+dp。先将所有单词 倒着 存进字典树,val为单词的长度。对于每一篇文章,bool f[i] 表示前i个字符能否被破解。其中如果前i个字母构成的字符串的后缀中有在字典树中存在的单词,则只需要看这篇文章去掉单词后缀后剩下的前面一段能否被破解。也就是说 只要存在任意 j,使得 f[ i - val[ j ] ] = true,那么 f[i]=true。最后只需找到最大的i使得 f[i]==true输出即可。
注意:我之前写了一支程序最后一个点TLE了,然后把一个返回vector的函数删了就好了。看来vector这种东西还是不能随便用。
代码:
#include<iostream>
#include<cstdio>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <stack>
#include <queue>
#include <deque>
#include <set>
#include <cstring>
#include <map>
using namespace std;
#define maxn 20
#define maxw 10
#define maxl 1000000
struct Trie {
int ch[maxn*maxw+5][30];
int val[maxn*maxw+5];
int sz;
bool f[maxl+5];
Trie() {
memset(ch,0,sizeof(ch));
memset(val,0,sizeof(val));
sz=0;
}
void insert(char* x,int len) {
int u=0;
for(int i=len-1; i>=0; i--) {
int y=x[i]-'a';
if(!ch[u][y]) {
ch[u][y]=++sz;
}
u=ch[u][y];
}
val[u]=len;
}
vector<int> find(char* x,int i) {
int u=0;
vector<int> vec;
for(int j=i; j>=0; j--) {
int y=x[j]-'a';
if(!ch[u][y]) return vec;
u=ch[u][y];
if(val[u]) vec.push_back(val[u]);
}
}
int query(char* x,int len) {
memset(f,0,sizeof(f));
f[0]=1;
for(int i=0; i<len; i++) {
int u=0;
for(int j=i; j>=0; j--) {
int y=x[j]-'a';
if(!ch[u][y]) break;
u=ch[u][y];
if(val[u]) {
if(f[i+1-val[u]]) f[i+1]=1;
}
}
}
for(int i=len; i>=1; i--) {
if(f[i]) return i;
}
return 0;
}
};
int n,m;
Trie trie;
int main() {
scanf("%d%d",&n,&m);
for(int i=0; i<n; i++) {
char x[maxw+5];
scanf("%s",x);
trie.insert(x,strlen(x));
}
for(int i=0; i<m; i++) {
char x[maxl+5];
scanf("%s",x);
printf("%d\n",trie.query(x,strlen(x)));
}
return 0;
}