【LA3942】Remember the Word【Trie】【计数DP】

来源:互联网 发布:考勤机软件下载 编辑:程序博客网 时间:2024/05/29 11:17

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=22&page=show_problem&problem=1943

大白上的题。

设dp[i]表示后缀S[i...L]的分解方案数,那么有dp[i] = ∑(dp[i + len(x)),单词x是S[i...L]的前缀。

每次转移,去trie里搜索S[i...L],如果遇到单词节点,那么加上dp[i + len(x)]。


给数组清零,没发现数组大小不一样,RE一发...

/* Footprints In The Blood Soaked Snow */#include <cstdio>#include <cstring>using namespace std;const int maxn = 300005, maxm = 4005, maxnode = 400005, p = 20071027;int n, dp[maxn], son[maxnode][27], cnt;bool flag[maxnode];char str[maxn], s[maxm];inline void insert(int len) {int now = 0;for(int i = 0; i < len; i++) {int &pos = son[now][s[i] - 'a'];if(!pos) pos = ++cnt;now = pos;}flag[now] = 1;}inline int calc(int x) {int now = 0, ans = 0;for(int i = x; i < n; i++) {int &pos = son[now][str[i] - 'a'];if(!pos) return ans;if(flag[pos]) ans = (ans + dp[i + 1]) % p;now = pos;}return ans;} int main() {int cas = 1;while(scanf("%s", str) != EOF) {for(int i = 0; i < maxnode; i++) flag[i] = 0;memset(son, 0, sizeof(son)); cnt = 0;scanf("%d", &n);for(int i = 1; i <= n; i++) {scanf("%s", s);insert(strlen(s));}n = strlen(str);dp[n] = 1;for(int i = n - 1; i >= 0; i--) dp[i] = calc(i);printf("Case %d: %d\n", cas++, dp[0]);}return 0;}


0 0
原创粉丝点击