題目鏈接:https://cn.vjudge.net/problem/UVALive-3942
題意:
給出一個由n個不同單詞組成的字典和一個長字符串s。把這個字符串分解成若干個單詞的連接(單詞可以重複使用),有多少種方法? 比如,有4個單詞 a,b,ac,cd, 則abcd有兩種分解方法: a+b+cd和ab+cd
s的長度<300000 , 1<=n<=4000, 每個單詞長度<=100
題解:
用dp[i]表示從字符i開始的字符串的分解方案數,dp[i]=sum(dp[i+len(x)]) 單詞x是s[i...L]的前綴。
如果枚舉單詞,每次需要枚舉4000多次,如果建一個字典樹,因爲每個字符串長度最長是100,所以在字典樹上跑,每次最多跑100次。
題目多組輸入,注意初始化。
代碼:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=3e5+5;
const int N=4000;
const int mod=20071027;
char c[N];
char s[maxn];
int son[N*100][26],tot;
bool cnt[N*100];
int dp[maxn];
void insert(char* c){
int len=strlen(c);
int p=0; //p爲結點在數組裏的下標
for(int i=0;i<len;i++){
int x=c[i]-'a';
if(son[p][x]==0) son[p][x]=++tot;
p=son[p][x];
}
cnt[p]=true;
}
int search(char *c,int pos){
int len=strlen(c);
int p=0;
int ans=0;
for(int i=0;i<len;i++){
int x=c[i]-'a';
if(son[p][x]==0) break;
p=son[p][x];
if(cnt[p]) ans=(ans+dp[pos+i+1])%mod;
}
return ans;
}
void init(){
memset(cnt,0,sizeof cnt);
memset(son,0,sizeof son);
tot=0;
}
int main(){
int cnt=1;
while(scanf("%s",s)!=EOF){
init();
int n;
scanf("%d",&n);
while(n--){
scanf("%s",c);
insert(c);
}
n=strlen(s);
dp[n]=1;
for(int i=n-1;i>=0;i--){
dp[i]=search(s+i,i);
}
printf("Case %d: %d\n",cnt++,dp[0]);
}
return 0;
}