首页 > 代码库 > UVALive 3942 Remember the Word

UVALive 3942 Remember the Word

空降链接:https://vjudge.net/problem/UVALive-3942

题意:

  给出一个字符串s(strlen(s)<=3e5)和一堆字符串str[MAX](MAX<=4000,strlen(str[i])<=100),每个str[i]可以用无限次,求用str这些字符串拼接成s的方案数。

题解:

  根据题意肯定要先建棵trie。。。然后开始xjbDP了。因为每个串的长度都<=100,所以每次可以枚举s的下标i作为起始坐标,在字典树中找当前下标为起点的前缀,如果在与字典树匹配中的某些串的结束位置与当前的s中的下标j匹配那么dp[j]+=dp[i-1]*tree[pos].ends。当然了,dp[0]=1,我的文本串的起始下标是1;

 

技术分享
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
const double eps = 1e-10;
const int maxn = 300000 + 100;
const int mod=20071027;
char ss[maxn],s[4005];
int n,dp[maxn],tt=0;
struct Trie {
    struct Tree {
        int c[26];
        int cc,ends;
        long long ans=0;
    }tree[4000*100+100];
    int cnt; long long ans;
    void init() {memset(tree,0,sizeof(tree)); cnt=ans=0;}
    void build(int pos,int x) {tree[pos].c[x]= ++cnt;}
    void insert(char* str) {
        int len=strlen(str),pos=0,ch;
        for(int i=0;i<len;++i) {
            ch=str[i]-a;
            if(!tree[pos].c[ch])build(pos,ch);
            pos=tree[pos].c[ch];
            tree[pos].cc++;
        }
        tree[pos].ends++;
    }
    void solve(char* str,int llen) {
        for(int i=1;i<=llen;++i) {
            int pos=0,ch=str[i]-a,pp=i;
            while(tree[pos].c[ch]&&pp<=llen) {
                pos=tree[pos].c[ch];
                if(tree[pos].ends) {
                    (dp[pp]+=(dp[i-1]*tree[pos].ends)%mod)%=mod;
                }
                pp++;
                ch=str[pp]-a;
            }
        }
    }
}trie;
int main() {
#ifdef ac
    freopen("in.txt" , "r" , stdin);
//    freopen("out.txt" , "w" , stdout);
#endif
    while(~scanf("%s",ss+1)) {
        trie.init(); int llen=strlen(ss+1);
        scanf("%d",&n);
        while(n--) scanf("%s",s),trie.insert(s);
        memset(dp,0,sizeof(dp));
        dp[0]=1;
        trie.solve(ss,llen);
        printf("Case %d: %d\n",++tt,dp[llen]);
    }
    return 0;
}
View Code

 

 

 

 

 

UVALive 3942 Remember the Word