LA 3942 背單詞(字首樹Trie dp)

2021-08-04 04:48:11 字數 1668 閱讀 7766

給出乙個由s個不同的單詞組成的字典和乙個長字串。把這個字串分解成若干個單詞的連線(單詞可以重複使用),有多少種方法?比如:有4個單詞a,b,cd,ab,則abcd有兩種分解方法:a+b+cd和ab+cd。

輸入格式:

多組資料,每組資料第一行為小寫字母組成的待分解字串,長度l不超過300000.第二行為單詞個數s(1<=s<=4000)。以下s行分別為乙個單詞,由不超過100個小寫字母組成。輸入結束eof。

分析:不難想到遞推計算方法,dp[n]=sum(dp[i+len[j]]),單詞j表示s[i…l]的字首。

如果先列舉j,在判斷是否為s[i…l]的字首,則時間o(4000*300000)超時,因此換個思路,先把所有單詞組成一棵trie數,有關trie數可以再下面部落格檢視。

然後再在trie數裡面查字首序列s[i…l],查詢沒經過乙個單詞節點,就找到了乙個上述狀態的j值,時間o(100*300000)足夠

**首先用藍書的trie樹模板,

struct trie

int idx(char c)

//插入字串s,附加資訊為v,注意v必須非0,因為0代表本節點不是單詞節點

void insert(const

char *s,int v)

u=ch[u][c];

}val[u]=v;

}//查詢**

void search(const

char *s,int len,vector

& ans)

}};

然後將資料進行樹插入,形成trie樹,再查詢每個單詞節點的權值,代入轉移方程中

#include 

#include

#include

#include

#include

#include

using

namespace

std;

#define maxnode 400010

const

int sig_size=101;

struct trie

int idx(char c)

//插入字串s,附加資訊為v,注意v必須非0,因為0代表本節點不是單詞節點

void insert(const

char *s,int v)

u=ch[u][c];

}val[u]=v;

}//查詢**

void search(const

char *s,int len,vector

& ans)

}};const

int mod= 20071027;

const

int maxs =4010;

const

int maxl = 300010;

int dp[maxl],len[maxs];

char str[maxl],word[110];

trie trie;

int main()

memset(dp,0,sizeof(dp));

int len1=strlen(str);

dp[len1]=1;

for(int i=len1-1; i>=0; i--)

/*abcd4a

babcd*/

LA3942 背單詞 trie樹 簡單動規)

問題描述 給出乙個由s個不同單詞組成的字典和乙個長字串。把這個字串分解成若干個單詞的連線 單詞可以重複使用 有多少種方法?比如4個單詞 則 abcd 有兩種分解方法 a b cd 或 ab cd 輸入格式 第一行為長字串 僅由小寫字母組成 第二行乙個整數n,表示字典包含的單詞數。以下n行,每行為乙個...

字串處理 Tire樹 LA3942

其實trie樹並沒有聽上去那麼高階。首先它是把所有的單詞存到了一棵樹裡面,說白了,就是按照乙個單詞的字首來存。不過這棵樹不需要按照嚴格意義上的樹來了,實際上,只需要用ch u i 來存就好了,而ch u i 代表的就是整棵樹,ch u i 的值為樹的節點值,即時遍歷的時間戳。u代表的是當前節點值,c...

背單詞訣竅

1,背單詞的五大訣竅 最重要的一點,就是 如果想比別人成功,就一定要走捷徑。不要期盼自己比別人幸運,也不要指望自己比別人更聰明或者更勤奮。從智力上說,從機遇上說,自己和別人都是差不了多少的,想超過和自己差不多的人,就一定要走捷徑,捷徑,捷徑!背單詞捷徑的第一條,就是 一定要每次都大量地背。因為自己不...