Trie字符串(Remember the Word, LA 3942)

Trie字符串(Remember the Word, LA 3942)

給出一個由S個不同單詞組成的字典和一個長字符串。把這個字符串分解成若干個單詞的連接(單詞可重複使用),有多少種方法?比如,有4個單詞a、b、cd、ab,則abcd有兩種分解方法:a+b+cd和ab+cd。
輸入格式:
輸入包含多組數據。每組數據第一行爲小寫字母組成的待分解字符串,長度不超過300000.第二行爲單詞個數S(1<=S<=4000)。一下S行每行爲一個單詞,由不超過10個小寫字母組成。輸入結束標誌爲文件結束符(EOF)
輸出格式:
對於每組數據,輸出分解方案數除以20071027的餘數。
分析:
用遞推+trie字符串
1、令d[i]表示從字符i開始的字符串(即後綴S[i…L])的分解方案數,則d[i] = sum{d[i + len(x)]|單詞x是S[i…L]的前綴}。
如果先枚舉x,再判斷它是否爲S[i…L]的前綴,時間無法承受(最多可能有4000個單詞,判斷還需要一段時間)換個思路,先把所有單詞組織成Trie,然後試着在Trie中“查找”S[i…L].查找過程中每經過一個單詞結點,就找到一個上述狀態轉移方程中的x,最多隻需比較100次就能找到所有x。

//
//  main.cpp
//  Trie字符串
//
//  Created by zhoujl on 15/10/29.
//  Copyright (c) 2015年 zhoujl. All rights reserved.
//
#include <cstring>
#include <cstdio>
#include <vector>
using namespace std;
const int maxn = 4000*100+3;
const int sigma_size = 26;
struct Trie {
    int ch[maxn][sigma_size];
    int sz;
    int val[maxn];
    void clear() {
        sz = 1;
        val[0] = 0;
        memset(ch[0], 0, sizeof(ch[0]));
    }
    int idx(char c) {
        return c - 'a';
    }
    void insert(char * s, int v) {
        int u = 0, n = strlen(s);
        for (int i = 0; i < n; i++) {
            int c = idx(s[i]);
            if (!ch[u][c]) {
                memset(ch[sz], 0, sizeof(ch[sz]));
                val[sz] = 0;
                ch[u][c] = sz++;
            }
            u = ch[u][c];
        }
        val[u] = v;
    }
    void find(const char * s, int len, vector<int>& ans) {
        int u = 0;
        for (int i = 0; i < len; i++) {
            int c = idx(s[i]);
            if (s[i] == '\0')
                break;
            if (!ch[u][c]) {
                return;
            }
            u = ch[u][c];
            if (val[u]) {
                ans.push_back(val[u]);
            }
        }

    }
};
const int MOD = 20071027;
const int maxl = 300000 + 10;
char text[maxl];
int d[4005];
char s[105];
Trie a;
int main() {
    int S;
    while (scanf("%s%d", text, &S) == 2) {
        a.clear();
        int len = strlen(text);
        getchar();
        memset(d, 0, sizeof(d));
        for (int i = 0; i < S; i++) {
            scanf("%s", s);
            int v = strlen(s);
            a.insert(s, v);
        }
        d[len] = 1;
        for (int i = len-1; i >= 0; i--) {
            vector<int> p;
            a.find(text+i, len-i, p);
            for(int j = 0; j < p.size(); j++)
                d[i] = (d[i] + d[i+p[j]]) % MOD;
        }
        printf("%d", d[0]);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章