【LA3942-Remember the word 】Trie
http://acm.hust.edu.cn/vjudge/problem/22109
题意:给定n个单词,一个字符串,问把这个字符串划分为若干个单词的连接(单词可重复使用)有多少种方案(mod20071027)。
题解:
设d[i]为从第i个字母开始的后缀有多少种匹配方案。
if 单词x是当前后缀的前缀: d[i]=sum{d(i+len(x))}
用所有单词建一棵trie,从后往前循环i,对于每一个i进入trie查找前缀,更新d[i]。
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> using namespace std; const int L=300100,Mod=20071027; char s0[L],s[L]; int n,num; int d[L],ch[L][30],bk[L]; void insert(char *c) { int l=strlen(c); int x=0; for(int i=0;i<l;i++) { int id=c[i]-'a'+1; if(!ch[x][id]) { num++; ch[x][id]=num; } x=ch[x][id]; } bk[x]=l; } void find(int l,int r) { int x=0; for(int i=l;i<=r;i++) { int id=s0[i]-'a'+1; if(!ch[x][id]) break; x=ch[x][id]; if(bk[x]) d[l]=(d[l]+d[l+bk[x]])%Mod; } } //d[i]=sum(d[i]+len(x)) int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int T=0; while(scanf("%s",s0)!=EOF) { num=0; memset(bk,0,sizeof(bk)); memset(ch,0,sizeof(ch)); memset(d,0,sizeof(d)); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%s",s); insert(s); } int l=strlen(s0); d[l]=1; for(int i=l-1;i>=0;i--) find(i,l-1); // for(int i=0;i<l;i++) printf("%d ",d[i]);printf("\n"); printf("Case %d: %d\n",++T,d[0]%Mod); } return 0; }