UVA_1401_Remerber the Word
给出一个由S个不同单词组成的字典和长字符串。把这个字符串分解成若干个单词的连接(单词可以重复使用),有多少种方法?比如,有4个单词a、b、cd、ab,则abcd有两种分解方法:a+b+cd和ab+cd。
待分解的字符串:长度L不超过300000
单词的个数:1<=S<=4000
思路:令d[i]表示从字符i开始的字符串的分解方案数,则d[i]=sum{d[i+len(x)] | 单词x是S[i..L]的前缀)},由它的递推性质可知,只需要从后往前遍历字符串,记录d[i],再累加就是答案
动态模板:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> using namespace std; #define mod 20071027 int dp[300008],num,re; struct Trie { Trie *child[26]; bool end; Trie() { end=0; for(int i=0;i<26;++i) child[i]=NULL; } }; Trie *root,*s; void Create(char *str) { s=root; int i=0; while(str[i]) { if(s->child[str[i]-'a']==0) { s->child[str[i]-'a']=new Trie; } s=s->child[str[i]-'a']; i++; //据说++i会更快 } s->end=1; } void Search(char *str,int pos) { s=root; int i=0; while(str[i]!=0&&s->child[str[i]-'a']) //以后的判断语句能不分开写就不分开了,分开与不分开居然差了几百MS,直接跪倒了我 { s=s->child[str[i]-'a']; if(s->end==1) //如果遇到是单词结尾的字符 { dp[pos]=dp[pos+i+1]?dp[pos]+dp[pos+i+1]:dp[pos]; //则num要加上从字符re+i+1开始的串的分解方案数 if(dp[pos]>=mod) dp[pos]-=mod; } i++; } } char a[300005]; int main() { int n,i,l,t=1; char b[105]; while(~scanf("%s",a)) { scanf("%d",&n); root=new Trie; for(i=0;i<n;++i) { scanf("%s",b); Create(b); } l=strlen(a); memset(dp,0,sizeof(dp)) ; dp[l]=1; for(i=l-1;i>=0;--i) { Search(a+i,i); //写成Search(&a[i],i)会更快 } printf("Case %d: %d\n",t++,dp[0]); } return 0; }
静态模板:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> using namespace std; #define mod 20071027 #define MAXN 400005 int dp[MAXN],num,p; char a[300005]; struct Trie { int child[26]; bool end; Trie() { end=0; memset(child,0,sizeof(child)); } void set() { end=0; memset(child,0,sizeof(child)); } }t[MAXN]; void Create(char *s) { int root=0,i=0,id; while(s[i]) { id=s[i]-'a'; if(t[root].child[id]==0) t[root].child[id]=p++; root=t[root].child[id]; i++; } t[root].end=1; } void Search(char *s,int pos) { int root=0,i=0; while(s[i]!=0&&t[root].child[s[i]-'a']) //条件判断能合在一起就合在一起,真是各种泪啊,合成一个之后居然可以省几百MS { root=t[root].child[s[i]-'a']; if(t[root].end) { dp[pos]=dp[pos+i+1]?dp[pos]+dp[pos+i+1]:dp[pos]; //则num要加上从字符re+i+1开始的串的分解方案数 if(dp[pos]>=mod) dp[pos]-=mod; } i++; } } int main() { int n,i,tt=1; char b[200]; while(~scanf("%s",a)) { scanf("%d",&n); p=1; memset(dp,0,sizeof(dp)); for(i=0;i<n;++i) { scanf("%s",b); Create(b); } int len=strlen(a); memset(dp,0,sizeof(dp)); dp[len]=1; //important for(i=len-1;i>=0;--i) { Search(&a[i],i); } printf("Case %d: %d\n",tt++,dp[0]); for(i=0;i<p;++i) //重新初始化 t[i].set(); } return 0; }
一个结构体的静态模板:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> using namespace std; #define mod 20071027 #define MAXN 300005 int dp[MAXN]; char a[MAXN]; struct Trie { int ch[MAXN][26]; bool val[MAXN]; int sz; void clear() { sz=1; memset(ch[0],0,sizeof(ch[0])); } void Create(char *s) { int u=0,n=strlen(s); for(int i=0;i<n;++i) { int c=s[i]-'a'; if(!ch[u][c]) { memset(ch[sz],0,sizeof(ch[sz])); val[sz]=0; ch[u][c]=sz++; } u=ch[u][c]; } val[u]=1; } void Search(char *s,int pos) { int i=0,u=0; while(s[i]!=0&&ch[u][s[i]-'a']) { u=ch[u][s[i]-'a']; if(val[u]) { dp[pos]=dp[pos+i+1]?dp[pos]+dp[pos+i+1]:dp[pos]; if(dp[pos]>=mod) dp[pos]-=mod; } ++i; } } }tr; int main() { int n,i,tt=1; char b[200]; while(~scanf("%s",a)) { scanf("%d",&n); tr.clear(); memset(dp,0,sizeof(dp)); for(i=0;i<n;++i) { scanf("%s",b); tr.Create(b); } int len=strlen(a); memset(dp,0,sizeof(dp)); dp[len]=1; //important for(i=len-1;i>=0;--i) { tr.Search(&a[i],i); } printf("Case %d: %d\n",tt++,dp[0]); } return 0; }