1. 程式人生 > >[UVA]UVA1401 remember the name(Trie)

[UVA]UVA1401 remember the name(Trie)

mod ++ 操作 uva set clas mes pri ember

題目大意:給出一個長度為n的字符串(n<=3e5)和一個單詞表(單詞長度不超過100),求該字符串被這些單詞表示的方案總數。

不難想到遞推算法:令f[s]為表示字符串s的方案總數,若某個單詞為s的前綴,f[s]=sum(f[x])(x為s去掉該單詞前綴的後綴字符串)

尋找字符串的前綴是trie的經典操作,把所有單詞插入trie中,然後在trie上dp即可。

PE了三次...

#include <bits/stdc++.h>

using namespace std;

typedef long long int LL;

#define st first
#define
nd second #define pb push_back #define mp make_pair #define pll pair <LL, LL> #define pii pair <int, int> #define rep(i,x) for(int i=1;i<=x;i++) const int N = 2e6+7; const int MX = 1e9+7; const LL INF = 1e18+9LL; const int mod = 20071027; string s; int n,cnt,l; int mem[300010
]; struct Trie{ int val[400010],ch[400010][26]; int sz=1; void init(){ memset(ch[0],0,sizeof(ch[0])); sz=1; } int index(char c){return c-a;}; void insert(char* s){ int u=0,l=strlen(s); for(int i=0;i<l;i++){ if(!ch[u][index(s[i])]){ memset(ch[sz],
0,sizeof(ch[sz])); val[sz]=0; ch[u][index(s[i])]=sz++; } u=ch[u][index(s[i])]; } val[u]=1; } }trie; int solve(int st){ if(st==l)return 1; if(mem[st]!=-1)return mem[st]; int res=0; int u=0; for(int i=st;i<l;i++){ if(trie.ch[u][trie.index(s[i])]){ if(trie.val[trie.ch[u][trie.index(s[i])]]){ res+=solve(i+1),res%=mod; } u=trie.ch[u][trie.index(s[i])]; } else break; } return mem[st]=res; } int main(){ while(cin>>s){ scanf("%d",&n); l=s.size(); for(int i=0;i<l;i++)mem[i]=-1; trie.init(); rep(i,n){ char a[120]; scanf("%s",a); trie.insert(a); //trie.print(0,""); } printf("Case%d:%d\n",++cnt,solve(0)); } }

[UVA]UVA1401 remember the name(Trie)