Bzoj 1212
题意:一段文章$T$是由若干小写字母构成。一个单词$W$也是由若干小写字母构成。一个字典$D$是若干个单词的集合。我们称一段文章T在某个字典$D$下是可以被理解的,是指如果文章$T$可以被分成若干部分,且每一个部分都是字典$D$中的单词。给定一个字典$D$,你的程序需要判断若干段文章在字典$D$下是否能够被理解。并给出其在字典$D$下能够被理解的最长前缀的位置。
容易发现若一个串$S$能被理解,那么$S+D_i$也能理解
那么我们就可以做一个存在性DP,按上面的来转移
我们发现单词长度不超过10,那么我们将单词插进Trie树,树高最高为10,那么直接暴力转移即可。具体可以看代码实现。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
#define ms(i, j) memset(i, j, sizeof i)
#define LL long long
#define db long double
#define fir first
#define sec second
#define mp make_pair
using namespace std;
namespace flyinthesky {
const int MAXN = 205;
int ch[MAXN][27], val[MAXN], sz, dp[1000000 + 5];
int n, m;
char s[1000000 + 5];
void insert() {
int len = strlen(s), now = 0;
for (int i = 0; i < len; ++i) {
int c = s[i] - 'a';
if (!ch[now][c]) ch[now][c] = ++sz;
now = ch[now][c];
if (i == len - 1) val[now] = 1;
}
}
int pro(int ith) {
dp[0] = ith;
int len = strlen(s + 1), ans = 0;
for (int i = 0; i <= len; ++i) {
if (dp[i] != ith) continue ; else ans = i;
int now = 0;
for (int j = i + 1; j <= len; ++j) {
int c = s[j] - 'a';
if (!ch[now][c]) break ;
now = ch[now][c];
if (val[now]) dp[j] = ith;
}
}
return ans;
}
void clean() {
ms(dp, 0), ms(ch, 0), ms(val, 0), sz = 0;
}
int solve() {
clean();
cin >> n >> m;
for (int i = 1; i <= n; ++i) scanf("%s", s), insert();
for (int i = 1; i <= m; ++i) {
scanf("%s", s + 1);
printf("%d\n", pro(i));
}
return 0;
}
}
int main() {
flyinthesky::solve();
return 0;
}
/*
4 3
is
name
what
your
whatisyouname
whatisyourname
whaisyourname
2 10
abc
bc
abcab
3 10
abcdefg
cde
5 10
abc
aba
c
bcbac
a
abacabcbacababcbacbcbbb
*/