UVALive 3942 字典树+dp


题意:给出一个字符串和n个不同的单词,求单词构成字符串的组合数,单词可以多次使用


题解:此字符串可以分解,dp[i]是此字符串的后缀str[i~len-1]的组成种数,则dp[i]=sum(dp[i+len(x)]|前缀为x(0~i-1))

建立一棵字典树,就可以在字典树上的一个分支上dp求解

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<algorithm>
#include<sstream>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
const int mod=20071027;
ll dp[300010];
char str[300010];
char ss[110];
struct trienode
{
    int w;
    struct trienode *nextx[26+5];
    trienode(){memset(nextx,0,sizeof(nextx)); w=0;};
};
struct trie
{
void inserttrie(struct trienode* &t,char* str)
{
    struct trienode* temp=t;
    int len=strlen(str);
    for(int i=0;i<=len-1;i++)
    {
        int k=str[i]-'a';
        if(temp->nextx[k]==NULL)
        {
            temp->nextx[k]=new trienode();
        }
        temp=temp->nextx[k];
    }
    temp->w++;
}
int searchtrie(struct trienode* t,int pos)
{
    struct trienode* temp=t;
    int len=strlen(str);
    ll ans=0;
    for(int i=pos;i<=len-1;i++)
    {
        int k=str[i]-'a';
        if(temp->nextx[k]==NULL)
            break;
        if(temp->nextx[k]->w!=0)
            ans=(ans+dp[i+1])%mod;
        temp=temp->nextx[k];
    }
    return ans;
}
void freetrie(struct trienode* &t)
{
    if(t==NULL)
        return ;
    for(int i=0;i<=25;i++)
        if(t->nextx[i])
        freetrie(t->nextx[i]);
    free(t);
}
}trie;
int main()
{
    int kase=1;
    while(scanf("%s",str)!=EOF)
    {
        int n;
        cin>>n;
        struct trienode* root=new trienode();
        for(int i=1;i<=n;i++)
            {
                scanf("%s",ss);
                trie.inserttrie(root,ss);
            }
        int len=strlen(str);
        dp[len]=1;
        for(int i=len-1;i>=0;i--)
            dp[i]=trie.searchtrie(root,i);

        printf("Case %d: %d\n",kase++,dp[0]);
       // cout<<"Case "<<kase++<<": "<<dp[0]<<endl;
       trie.freetrie(root);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值