算法竞赛经典训练指南p209
题意
给定一些单词,和一个长串,问这个长串拆分成已有单词,能拆分成几种方式
trie基本模板
int ch[maxn][30]; //ch[i][j]:结点i的第j个字符对应结点号
int val[maxn];
int tot;
struct trie{
trie(){
tot=1;
memset(ch[0],0,sizeof(ch[0]));
}
int idx(char c){
return c-'a';
}
void insert(char *s,int w){
int u=0,n=strlen(s);
for(int i=0;i<n;i++){
int v=idx(s[i]);
if(!ch[u][v]){
memset(ch[tot],0,sizeof(ch[tot]));
val[tot]=0;
ch[u][v]=tot++;
}
u=ch[u][v];
}
val[u]=w;
}
int query(char *s){
int u=0,n=strlen(s);
for(int i=0;i<n;i++){
int v=idx(s[i]);
u=ch[u][v];
if(u==0) return 0;
}
return val[u];
}
};
AC code
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=1e6+5;
const int mod=20071027;
const int inf=1e18;
/************/
char a[maxn],b[5005][105];
int n,go=1,len,dp[maxn]; //dp[i]:从第i个字符至结尾可行的分解方案数
int ch[maxn][30]; //ch[i][j]:结点i的第j个字符对应结点号
int val[maxn];
int tot;
struct trie{
trie(){
tot=1;
memset(ch[0],0,sizeof(ch[0]));
}
int idx(char c){
return c-'a';
}
void insert(char *s,int w){
int u=0,n=strlen(s);
for(int i=0;i<n;i++){
int v=idx(s[i]);
if(!ch[u][v]){
memset(ch[tot],0,sizeof(ch[tot]));
val[tot]=0;
ch[u][v]=tot++;
}
u=ch[u][v];
}
val[u]=w;
}
int query(char *s){
int u=0,n=strlen(s);
for(int i=0;i<n;i++){
int v=idx(s[i]);
u=ch[u][v];
if(u==0) return 0;
}
return val[u];
}
//上述为基本模板
void cal(int i){
int u=0;
dp[i]=0;
for(int j=i;j<=len;j++){
int v=idx(a[j]);
u=ch[u][v];
if(u==0) return;
if(val[u]) dp[i]=(dp[i]+dp[j+1])%mod;
}
}
};
signed main()
{
while(~scanf("%s",a+1)){
len=strlen(a+1);
struct trie tree;
scanf("%lld",&n);
for(int i=1;i<=n;i++) dp[i]=0;
for(int i=1;i<=n;i++){
scanf("%s",b[i]);
tree.insert(b[i],1);
}
dp[len+1]=1;
for(int i=len;i>=1;i--){
tree.cal(i);
}
printf("Case %lld: %lld\n",go++,dp[1]);
}
return 0;
}
时间复杂度
O(nlogn)