在上一篇的解法中,我们使用Trie树优化的dp,复杂度达到
3e9
,限时3s,奇迹般地跑了2.929sAC了。然鹅。。。这并不是使用Trie的正确姿势。
Trie树是从根节点向下查找,如果我们计算的顺序和它一致,会大大降低复杂度。
重新定义
dpi
为字符串
s
的后缀
则,
dpi=∑s[i,j]在Trie中dpj+1
。
这样对于 dpi , j 可以按从
#include<bits/stdc++.h>
typedef long long LL;
typedef unsigned long long ull;
using namespace std;
const int maxn = 3e5+5;
const int maxn2 = 400000+8;
const int maxm = 26;
const int maxn3 = 105;
const int M = 20071027;
char s[maxn], s2[maxn3];
struct Trie
{
int ch[maxn2][maxm];
bitset<maxn2> val;
int tot = 1;
void init()
{
memset(ch[0], 0, sizeof ch[0]);
val.reset();
tot = 1;
}
void add(char *s)
{
int n = strlen(s);
int cur = 0, id;
for(int i = 0; i < n; ++i)
{
id = s[i] - 'a';
if(!ch[cur][id])
{
memset(ch[tot], 0, sizeof ch[tot]);
ch[cur][id] = tot++;
}
cur = ch[cur][id];
}
val[cur] = 1;
}
bool finda(char *s)
{
int n = strlen(s);
int cur = 0, id;
for(int i = 0; i < n; ++i)
{
id = s[i] - 'a';
if(!ch[cur][id]) return false;
cur = ch[cur][id];
}
return val.test(cur);
}
}tr;
LL dp[maxn];
int main()
{
int Case = 1;
while(~scanf("%s", s+1))
{
int n;
cin >> n;
int len = strlen(s+1);
tr.init();
for(int i = 0; i < n; ++i)
{
scanf("%s", s2);
tr.add(s2);
}
memset(dp, 0, sizeof dp);
dp[len + 1] = 1;
for(int i = len; i >= 1; --i)
{
int cur = 0, id;
for(int j = i; j <= len; ++j)
{
id = s[j] - 'a';
if(!tr.ch[cur][id]) break;
cur = tr.ch[cur][id];
if(tr.val[cur]) dp[i] = (dp[i] + dp[j+1])%M;
}
}
printf("Case %d: ", Case++);
cout << dp[1] << endl;
}
return 0;
}