Trie+DP
大白书上的字典树训练题。
题意是说一个字符串可能有多少种小串组成。
例如
abcd
4
a
b
cd
ab
abcd=a+b+cd;abcd=ab+cd;
递推为:从最后一位往前,dp[i]=dp[i]+dp[i+ len[x]] x为输入时的顺序,附加到节点中。是 i~strlen(S)的前缀。S[1,2,3,…,i,…len]
构建Trie树时,把顺序也附加到节点中。
最后search的时候 找出为多少个字符串的前缀,并把这些前缀都加起来。
#include<cstdio> #include<cstring> #include<string> #include<queue> #include<algorithm> #include<map> #include<stack> #include<iostream> #include<list> #include<set> #include<cmath> #define INF 0x7fffffff #define eps 1e-6 #define LL long long using namespace std; const int MOD=20071027; struct Trie { int word[4001*100][26]; int ex[4001*100]; int size; void clear() { memset(word[0],0,sizeof(word[0])); size=1; ex[0]=0; } int insert(char *s,int v) { int u=0,c; for(int i=0; s[i]!='\0'; i++) { int c=s[i]-'a'; if(!word[u][c]) { memset(word[size],0,sizeof(word[size])); ex[size]=0; word[u][c]=size++; } u=word[u][c]; } ex[u]=v; } int search(char *s,int len,vector<int>& ans) { int u=0,c; for(int i=0; s[i]!='\0'&&i<len; i++) { c=s[i]-'a'; if(!word[u][c])return 0; u=word[u][c]; if(ex[u]) ans.push_back(ex[u]); } } } wo; char str[300001]; int dp[300001]; int n; int le[4001]; int main() { int nn=1; while(scanf("%s",str)!=EOF) { scanf("%d",&n); wo.clear(); memset(dp,0,sizeof(dp)); char tmp[101]; int len=strlen(str); for(int i=0; i<n; i++) { scanf("%s",tmp); le[i+1]=strlen(tmp); wo.insert(tmp,i+1); } dp[len]=1; for(int i=len-1; i>=0; i--) { vector<int>ans; wo.search(str+i,len-i,ans); for(int j=0; j<ans.size(); j++) dp[i]=(dp[i]+dp[i+le[ans[j]]])%MOD; } printf("Case %d: %d\n",nn++,dp[0]); } }
UVa 1401 Remember the Word,布布扣,bubuko.com
原文地址:http://blog.csdn.net/dongshimou/article/details/37907679