Uva1401/LA3942 Remember the Word(trie模板)

LRJ书上例题,但是自己在思考过程中挺有收获。。。。
UVA1401题目直达
题目大意是拆解字符串,有几种方法。
简单思路:设 dp[i] 为字符串从第i位开始的拆解方法;仔细一想的话就会发现这样的关系:

dp[i]=j[1,S]dp[i+len[j]]

其中 S <script type="math/tex" id="MathJax-Element-156">S</script>为单词总数,j为单词编号。
使用trie可以实现,AC代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>

using namespace std;
const int maxn=500000;
const int mod=20071027;

char buffer[maxn];
int dp[maxn];
int mark[maxn];
char word[5000][200];
int n;

    int val[maxn];
    int ch[maxn][27];
    int sz;
    void ini()
    {
        sz=1;
        memset(val,0,sizeof(val));
        memset(ch,0,sizeof(ch));
        memset(dp,0,sizeof(dp));
        memset(mark,0,sizeof(mark));
        memset(word,0,sizeof(word));
    }
    int ind(char c)
    {
        return c-'a';
    }


    void insert(char *s,int v)
    {
        int len=strlen(s);
        int u=0;
        for(int i=0;i<len;i++)
        {
            int num=ind(s[i]);
            if(!ch[u][num])
            {
                ch[u][num]=sz;
                sz++;
            }
            u=ch[u][num];
        }
        val[u]=v;
    }

    bool queryeach(char *s)
    {
        int parent=0;
        int len=strlen(s);
        for(int i=0;i<len;i++)
        {
            int num=ind(s[i]);
            if(ch[parent][num]==0)
            {
                return false;
            }
            parent=ch[parent][num];
        }
        return (val[parent]>0);
    }

    vector<int > query(char *s)
    {
        int parent=0;
        vector<int > ans;
        int len=strlen(s);
        for(int i=0;i<len;i++)
        {
            int num=ind(s[i]);
            if(!ch[parent][num])
            {
                break;
            }
            if(val[ch[parent][num]]!=0)
            {
                ans.push_back(val[ch[parent][num]]);
            }
            parent=ch[parent][num];

        }
        /*
        for(unsigned i=0;i<ans.size();i++)
        {
            printf("%d ",ans[i]);
        }
        printf("\n");
        */
        return ans;
    }

char kagami[maxn];

int main()
{
    //freopen("1.out","w",stdout);
    int cas=0;
    while(~scanf("%s",buffer))
    {
        cas++;
        scanf("%d",&n);
        ini();
        int maxlen=0;
        for(int i=0;i<n;i++)
        {
            memset(kagami,0,sizeof(kagami));
            scanf("%s",kagami);
            int len=strlen(kagami);
            mark[len]++;
            maxlen=max(maxlen,len);
            strcpy(word[i],kagami);
            insert(kagami,len);
        }

        //初始化
        int len=strlen(buffer);
        for(int i=1;i<=maxlen;i++)
        {
            if(mark[i]>0)
            {
                bool flag=queryeach(buffer+len-i);
                if(flag)
                {
                    dp[len-i]=(dp[len-i]+1+mod)%mod;
                }
            }
        }
        /*
        for(int i=0;i<=len;i++)
        {
            printf("dp[%d]=%d\n",i,dp[i]);
        }
        printf("\n");
        */
        dp[len]=0;
        for(int i=len-1;i>=0;i--)
        {
            vector<int> res=query(buffer+i);
            /*
            for(unsigned j=0;j<res.size();j++)
            {
                printf("res[%d]=%d\n",j,res[j]);
            }
            printf("\n");
            */
            for(unsigned j=0;j<res.size();j++)
            {
                dp[i]=(dp[i]+dp[i+res[j]]+mod)%mod;
            }
        }
        /*
        for(int i=0;i<=len;i++)
        {
            printf("dp[%d]=%d\n",i,dp[i]);
        }
        */
        printf("Case %d: %d\n",cas,(dp[0]+mod)%mod);
    }
    return 0;
}

调了一段时间,不过收获还是比较大的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值