题意:给定一个长度不超过30000的字符串str,然后给定n(n<=4000)个长度不超过100的字符串ai,问用ai组合成str有多少种方案数,最终结果mod20071027。
题解:这里dp[i]表示从len到字符串i有dp[i]种方案,那么前一种的转态dp[i+1]的组合数是由(dp[i+1],i)这一段组成的,我们如何枚举i这一段,如果直接暴力枚举的复杂度将所有子串枚举一遍,O(1e5),然而这只是一次的枚举量,考虑使用tire树,因为子串的长度不会超过100,那么4000个子串我只要在trie树里最多只要查找100个节点就可以了,达到了加速的目的.
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxnode int(4e5+10)
#define sigma_size int(26)
#define mod int(20071027)
using namespace std;
char tmp[200];
char st[maxnode];
int dp[maxnode];
int ch[maxnode][sigma_size];
int val[maxnode];
struct trie
{
int sz;
trie() { sz = 1; memset(ch[0], 0, sizeof(ch[0])); }
int idx(char c) { return c - 'a'; }
void insert(char *s, int v)
{
int u = 0, n = strlen(s);
for (int i = 0; s[i]; i++)
{
int c = idx(s[i]);
if (!ch[u][c])
{
memset(ch[sz], 0, sizeof(ch[sz]));
val[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u] = v;
}
int find(char *s, int pos)
{
int ans = 0;
int u = 0, n = strlen(s);
for (int i = pos; i < n&&i<=pos+100; i++)
{
int c = idx(s[i]);
if (!ch[u][c]) return ans;
u = ch[u][c];
if (val[u])
ans= (dp[i+1] + ans) % mod;
}
return ans;
}
}tree;
int main()
{
#ifdef CDZSC
freopen("i.txt", "r", stdin);
#endif
int n,cas=0;
while (~scanf("%s", st))
{
tree = trie();
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%s", tmp);
tree.insert(tmp, 1);
}
int len = strlen(st);
dp[len] = 1;
for (int i = len - 1; i >= 0; i--)
{
dp[i] = tree.find(st, i);
}
printf("Case %d: %d\n",++cas, dp[0]);
}
return 0;
}