题目大意
将给定长度为L的字符串S 用字典中单词分解 单词可重复使用 问有多少分解方案数
大体思路
dp[i]表示从i开始的字符串(后缀)的分解方案数 dp[i]=∑dp[i+len(x)] x为字符串S[i...L]的前缀
将单词组成Trie 然后在Trie中查找前缀 找到后递推dp[i]即可
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include<queue>
using namespace std;
const int maxn=300010;
const int mod=20071027;
char r[maxn];
int dp[maxn];
struct Trie
{
int ch[maxn][26];
int val[maxn];
int sz;
void res(){
sz=1;
memset(ch[0],0,sizeof ch[0]);
memset(val,0,sizeof val);
}
int idx(char c) {
return c-'a';
}
void insert(char *s,int v) {
int u = 0,n=strlen(s);
for(int i = 0; i < n; ++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;
}
void query(char *s,int pos)
{
int u=0,n=strlen(s);
for(int i = 0;i<n;++i) {
int c=idx(s[i]);
if(!ch[u][c]) return ;
u=ch[u][c];
if(val[u]) {
dp[pos]=(dp[pos]+dp[pos+i+1])%mod;
}
}
}
};
Trie trie;
int n;
char temp[105];
int main()
{
// freopen("in.txt","r",stdin);
int Kase=0;
while(~scanf("%s",r)) {
printf("Case %d: ",++Kase);
trie.res();
memset(dp,0,sizeof dp);
int l=strlen(r);
dp[l]=1;
scanf("%d",&n);
for(int i = 0; i < n; ++i) {
scanf("%s",temp);
trie.insert(temp,strlen(temp));
}
for(int i = l-1;i>=0;--i) {
trie.query(r+i,i);
}
printf("%d\n",dp[0]);
}
return 0;
}