UVA - 1401-------trie&&dp

Remember the Word UVA - 1401(传送门)

题意:

给你一个字典。和一个模式串。
现在要求你按照字典分割模式串。

方案数。

思路:

很容易想到递推的思想。
之后就是怎样递推。
这里为了使用trie,所以倒着dp。
dp【i】=dp【i】+dp【i+len【x】】。(这里表示对于s【i,len】中,找到一个前缀,这个前缀在字典里,之后转移。len【x】表示这个前缀的长度)

AC

#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#define For(i,x,y) for(int i=(x); i<=(y); i++)
using namespace std;
const int maxnode=4000*100+10;///最多有多少层
const int sigma_size=26;///字母的话就是26
const int maxn=4000+10;
const int maxm=3e5+10;
const int mod=20071027;
int len[maxn];
char text[maxm];
struct Tire{
    int ch[maxnode][sigma_size];///ch[u][0]代表这个结点不存在
    int val[maxnode];///结点的权值(相当于标记是否为一个字符串的最后一个元素)
    int sz;///结点总数
    void clear(){sz=1; memset(ch[0],0,sizeof(ch[0])); }
   // Tire(){sz=1; memset(ch[0],0,sizeof(ch[0])); }///初始化第一个根结点
    int idx(char c){return c-'a';}
    //
    ///插入字符串s,附加信息v(权值)。注意v必须非0,因为0代表“本结点不是单词结点”
    void insert(char *s, int v){
        int u=0, len_s=strlen(s);
        for(int i=0; i<len_s; i++){
            int c=idx(s[i]);
            if(!ch[u][c]){///结点不存在
                memset(ch[sz],0,sizeof(ch[sz]));
                val[sz]=0;///中间结点的附加信息为0.
                ch[u][c]=sz++;///新建结点
            }
            u=ch[u][c];///往下走。
            //cout<<u<<endl;
        }
        val[u]=v;///最后一个字符的附加信息为v。
    }
    void find_pre(char *s, int len_s, vector<int>&ans){
        int u=0;
        for(int i=0; i<len_s; i++){
            int c=idx(s[i]);
            if(!ch[u][c])break;
            u=ch[u][c];
            if(val[u])ans.push_back(val[u]);
        }
    }
}tire;
void init(){
    int num;
    scanf("%d", &num);
    For(i,1,num){
        char s[200];
        scanf("%s", s);
        tire.insert(s,i);
        len[i]=strlen(s);
    }
}
int dp[maxm];
int work(){
    int len_text=strlen(text);
    dp[len_text]=1;
    for(int i=len_text-1; i>=0; i--){
        vector<int>p;dp[i]=0;
        tire.find_pre(text+i, len_text-i,p);
        //cout<<"p.size()-----"<<p.size()<<endl;
        for(int j=0; j<p.size(); j++)dp[i]=(dp[i]+dp[ i+len[p[j]] ])%mod;
        //cout<<"dp[i]------"<<dp[i]<<endl;
    }
    return dp[0];
}
int main()
{
    int kase=0;
    while(~scanf("%s", text)){
        tire.clear();
        init();
        printf("Case %d: %d\n", ++kase,work());
    }
    return 0;
}
/*
abcd
4
a
b
cd
ab
*/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值