题目:
思路: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 1000000struct 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;
}