题意:
给出一个由多个不同单词组成的字典,和一个长字符串,把这个字符串分解成若干个单词的连接,问有多少种方法;
思路:
dp[i]表示s[i,L]的方案数,d[i]=∑d[j];s[i,j-1]是一个字典里的单词;
一开始想用mp搞,最后t了;换成了trie树,由于单词的长度不超过100,所以就可以在trie树查找不超过100的长度,把出现单词结点的累加;dp[0]就是答案了;
AC代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <bits/stdc++.h> #include <stack> using namespace std; #define For(i,j,n) for(int i=j;i<=n;i++) #define mst(ss,b) memset(ss,b,sizeof(ss)); typedef long long LL; template<class T> void read(T&num) { char CH; bool F=false; for(CH=getchar();CH<'0'||CH>'9';F= CH=='-',CH=getchar()); for(num=0;CH>='0'&&CH<='9';num=num*10+CH-'0',CH=getchar()); F && (num=-num); } int stk[70], tp; template<class T> inline void print(T p) { if(!p) { puts("0"); return; } while(p) stk[++ tp] = p%10, p/=10; while(tp) putchar(stk[tp--] + '0'); putchar(' '); } const LL mod=20071027; const double PI=acos(-1.0); const int inf=1e9; const int N=4e5+10; const int maxn=500+10; const double eps=1e-8; //map<string,int>mp; LL dp[N]; char s[N],str[110]; int sz=0; int ch[N][28],val[N]; inline void Init() { mst(ch,0); sz=1; mst(val,0); } inline void insert() { int u=0,len=strlen(str); For(i,0,len-1) { int temp=str[i]-'a'; if(!ch[u][temp]) { //mst(ch[sz],0); val[sz]=0; ch[u][temp]=sz++; } u=ch[u][temp]; } val[u]=1; } inline LL query(int l,int r) { LL ans=0; int u=0; for(int i=l;r<=r;i++) { int temp=s[i]-'a'; if(ch[u][temp]) { int x=ch[u][temp]; if(val[x])ans=(ans+dp[i+1])%mod; u=x; } else break; } return ans; } int main() { int Case=0; while(scanf("%s",s)!=EOF) { Init(); printf("Case %d: ",++Case); int q,len=strlen(s); read(q); while(q--) { scanf("%s",str); insert(); } dp[len]=1; for(int i=len-1;i>=0;i--) { dp[i]=0; int r=min(len-1,i+100); dp[i]=query(i,r); } printf("%lld ",dp[0]); } return 0; }