Trie树

暂时没学懂,先把板子放这吧。

题意:给出一个字符串和S个单词组成的字典,问把这个字符串分解成若干单词的连接,总共有多少种?(单词可重复)

思路:令d[i]表示从字符i开始的字符串的分解方案数,则dans[i]=sum{dans[i+d[x]] | 单词x是S[i…len]的前缀};

#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
typedef long long LL;
const int maxn=300010;
const int MOD=20071027;
int d[maxn],len;
vector<int> ans;
struct node
{
    node *next[30];
    int value;
    int num;
    node()
    {
        for(int i=0;i<30;i++)
            next[i]=NULL;
        value=0;
    }
}root;
string a;
int n;
void insert(string s)
{
    node *p=&root;
    int k=0,l=s.size();
    while(k<l)
    {
        if(!p->next[s[k]-'a'])
            p->next[s[k]-'a']=new node;
        p=p->next[s[k]-'a'];
        k++;
    }
    p->value=l;
}
void find(int x)
{
    ans.clear();
    node *p=&root;
    int y=x;
    while(x<len&&p->next[a[x]-'a']!=NULL)
    {
        if(p->next[a[x]-'a']->value)
        ans.push_back(p->next[a[x]-'a']->value);
        p=p->next[a[x]-'a'];
        x++;
    }
}
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
    #endif
    int t=1;
    string x;
    while(cin>>a)
    {
        cin>>n;
        len=a.size();
        for(int i=0;i<30;i++)
        root.next[i]=NULL;
        for(int i=0;i<n;i++)
        {
            cin>>x;
            insert(x);
        }
        memset(d,0,sizeof(d));
        d[len]=1;
        for(int i=len-1;i>=0;i--)
        {
            find(i);
            for(int j=0;j<ans.size();j++)
            d[i]=(d[i]+d[i+ans[j]])%MOD;
        }
        cout<<"Case "<<t++<<": ";
        cout<<d[0]<<endl;
    }
    return 0;
}

或者直接在find的时候更新d数组

#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long LL;
const int maxn=300010;
const int MOD=20071027;
int d[maxn],len;
struct node
{
    node *next[30];
    int value;
    int num;
    node()
    {
        for(int i=0;i<30;i++)
            next[i]=NULL;
        value=0;
    }
}root;
string a;
int n;
void insert(string s)
{
    node *p=&root;
    int k=0,l=s.size();
    while(k<l)
    {
        if(!p->next[s[k]-'a'])
            p->next[s[k]-'a']=new node;
        p=p->next[s[k]-'a'];
        k++;
    }
    p->value=1;
    p->num++;
}
void find(int x)
{
    node *p=&root;
    int y=x;//cout<<(p->next[a[x]-'a']==NULL)<<endl;
    while(x<len&&p->next[a[x]-'a']!=NULL)
    {
        if(p->next[a[x]-'a']->value)d[y]=(d[y]+d[x+1])%MOD;
        p=p->next[a[x]-'a'];
        x++;
    }
}
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
    #endif
    int t=1;
    string x;
    while(cin>>a)
    {
        cin>>n;
        len=a.size();
        for(int i=0;i<30;i++)
        root.next[i]=NULL;
        for(int i=0;i<n;i++)
        {
            cin>>x;
            insert(x);
        }
        memset(d,0,sizeof(d));
        d[len]=1;
        for(int i=len-1;i>=0;i--)
            find(i);
        cout<<"Case "<<t++<<": ";
        cout<<d[0]%20071027<<endl;
    }
    return 0;

作者:u010660276
来源:CSDN
原文:https://blog.csdn.net/u010660276/article/details/19678289
版权声明:本文为博主原创文章,转载请附上博文链接!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值