UVA

https://vjudge.net/problem/UVA-1401

题意

给出S个不同的单词作为字典,还有一个长度最长为3e5的字符串。求有多少种方案可以把这个字符串分解为字典中的单词。

分析

首先强烈吐槽,vjudge上的UVALive 3942怎么都过不了。。。然而题目一模一样的UVA 1401就稳稳地过了。。。很玄学。

根据题意可以想到一个dp,dp[i]表示从第i个字符开始的字符串的分解方案。那么dp[i]=dp[i]+dp[i+len(x)],其中单词x为匹配的前缀。

如此,从后开始枚举i,每次都走一遍trie,找对应前缀的单词节点,然后计数。初始化dp[len]=1,为了让dp[len-1]能正确转移。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define ms(a, b) memset(a, b, sizeof(a))
#define pb push_back
#define mp make_pair
#define pii pair<int, int>
//#define eps 0.0000000001
#define IOS ios::sync_with_stdio(0);cin.tie(0);
#define random(a, b) rand()*rand()%(b-a+1)+a
#define pi acos(-1)
//const ll INF = 0x3f3f3f3f3f3f3f3fll;
const int inf = 0x3f3f3f3f;
const int maxn = 3e5 + 10;
const int maxm = 4e5 +10;
const int mod = 20071027;
const int sigma_size = 26;
char s[maxn];
ll dp[maxn];
struct Trie{
    int ch[maxm][sigma_size];
    bool val[maxm];
    int sz;
    void init(){
        sz=1;
        memset(ch[0],0,sizeof(ch[0]));
        memset(val,0,sizeof(val));
    }
    int idx(char c) { return c-'a'; }
    void insert(char* s){
        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]=false;
                ch[u][c]=sz++;
            }
            u=ch[u][c];
        }
        val[u]=true;
    }
    void query(char* s){
        int len=strlen(s);
        memset(dp,0,sizeof(dp));
        dp[len]=1;
        for(int i=len-1;i>=0;i--){
            int u=0;
            for(int j=i;j<len;j++){
                int c = idx(s[j]);
                if(!ch[u][c]) break;
                u=ch[u][c];
                if(val[u]) dp[i]=(dp[i]+dp[j+1])%mod;
            }
        }
    }
};
Trie trie;
char tmp[110];
int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
//    freopen("input.txt", "w", stdout);
#endif
    int cas=1;
    while(~scanf("%s",s)){
        trie.init();
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            scanf("%s",tmp);
            trie.insert(tmp);
        }
        trie.query(s);
        printf("Case %d: %lld
",cas++,dp[0]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/fht-litost/p/9626362.html