[UVA]UVA1401 remember the name(Trie)

题目大意:给出一个长度为n的字符串(n<=3e5)和一个单词表(单词长度不超过100),求该字符串被这些单词表示的方案总数。

不难想到递推算法:令f[s]为表示字符串s的方案总数,若某个单词为s的前缀,f[s]=sum(f[x])(x为s去掉该单词前缀的后缀字符串)

寻找字符串的前缀是trie的经典操作,把所有单词插入trie中,然后在trie上dp即可。

PE了三次...

#include <bits/stdc++.h>

using namespace std;

typedef long long int LL;

#define st first
#define nd second
#define pb push_back
#define mp make_pair
#define pll pair <LL, LL>
#define pii pair <int, int>
#define rep(i,x) for(int i=1;i<=x;i++)

const int N = 2e6+7;
const int MX = 1e9+7;
const LL INF = 1e18+9LL;
const int mod = 20071027;

string s;

int n,cnt,l;

int mem[300010];

struct Trie{
    int val[400010],ch[400010][26];
    int sz=1;
    void init(){
        memset(ch[0],0,sizeof(ch[0]));
        sz=1;
    }
    int index(char c){return c-'a';};
    void insert(char* s){
        int u=0,l=strlen(s);
        for(int i=0;i<l;i++){
            if(!ch[u][index(s[i])]){
                memset(ch[sz],0,sizeof(ch[sz]));
                val[sz]=0;
                ch[u][index(s[i])]=sz++;
            }
            u=ch[u][index(s[i])];
        }
        val[u]=1;
    }
    
}trie;

int solve(int st){
    if(st==l)return 1;
    if(mem[st]!=-1)return mem[st];
    int res=0;
    int u=0;
        for(int i=st;i<l;i++){
            if(trie.ch[u][trie.index(s[i])]){
                if(trie.val[trie.ch[u][trie.index(s[i])]]){
                    res+=solve(i+1),res%=mod;
                    }
                u=trie.ch[u][trie.index(s[i])];
            }
            else break;
        }
    return mem[st]=res;
}




int main(){
    while(cin>>s){
        scanf("%d",&n);
        l=s.size();
        for(int i=0;i<l;i++)mem[i]=-1;
        trie.init();
        rep(i,n){
            char a[120];
            scanf("%s",a);
            trie.insert(a);
            //trie.print(0,"");
        }
        
        printf("Case%d:%d
",++cnt,solve(0));
    }
}
原文地址:https://www.cnblogs.com/xutianshu/p/10459375.html