题意:给出一个字符串和n个不同的单词,求单词构成字符串的组合数,单词可以多次使用
题解:此字符串可以分解,dp[i]是此字符串的后缀str[i~len-1]的组成种数,则dp[i]=sum(dp[i+len(x)]|前缀为x(0~i-1))
建立一棵字典树,就可以在字典树上的一个分支上dp求解
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<algorithm>
#include<sstream>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
const int mod=20071027;
ll dp[300010];
char str[300010];
char ss[110];
struct trienode
{
int w;
struct trienode *nextx[26+5];
trienode(){memset(nextx,0,sizeof(nextx)); w=0;};
};
struct trie
{
void inserttrie(struct trienode* &t,char* str)
{
struct trienode* temp=t;
int len=strlen(str);
for(int i=0;i<=len-1;i++)
{
int k=str[i]-'a';
if(temp->nextx[k]==NULL)
{
temp->nextx[k]=new trienode();
}
temp=temp->nextx[k];
}
temp->w++;
}
int searchtrie(struct trienode* t,int pos)
{
struct trienode* temp=t;
int len=strlen(str);
ll ans=0;
for(int i=pos;i<=len-1;i++)
{
int k=str[i]-'a';
if(temp->nextx[k]==NULL)
break;
if(temp->nextx[k]->w!=0)
ans=(ans+dp[i+1])%mod;
temp=temp->nextx[k];
}
return ans;
}
void freetrie(struct trienode* &t)
{
if(t==NULL)
return ;
for(int i=0;i<=25;i++)
if(t->nextx[i])
freetrie(t->nextx[i]);
free(t);
}
}trie;
int main()
{
int kase=1;
while(scanf("%s",str)!=EOF)
{
int n;
cin>>n;
struct trienode* root=new trienode();
for(int i=1;i<=n;i++)
{
scanf("%s",ss);
trie.inserttrie(root,ss);
}
int len=strlen(str);
dp[len]=1;
for(int i=len-1;i>=0;i--)
dp[i]=trie.searchtrie(root,i);
printf("Case %d: %d\n",kase++,dp[0]);
// cout<<"Case "<<kase++<<": "<<dp[0]<<endl;
trie.freetrie(root);
}
return 0;
}