UVALive - 3942 Remember the Word

第一道AC自动机+DP,自己好菜连一个线性DP都不会,还得去看博客。
大佬  Orz <一蒟蒻(我)

题意:给你一个文本串,再给你几个单词,用单词组成文本串的方案数(单词不能重叠)。

 

我的思路:用AC自动机跑出文本串中出现单词区间[s,e](我的代码中的e表示单词结束位置的后一位,为了方便dp),

DP方程:dp[i]表示i到文本串结尾的方案数    dp[i]=sum{d[i+len(x)]|x是从i位置出现过的单词}

虽然这样能够,但是感觉写法很傻逼。。。大佬是直接在树上DP。

大佬博客:https://www.cnblogs.com/candy99/p/5959943.html

我的傻逼代码:

///#include<bits/stdc++.h>
///#include<unordered_map>
///#include<unordered_set>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<bitset>
#include<set>
#include<stack>
#include<map>
#include<list>
#include<new>
#include<vector>
#define MT(a,b) memset(a,b,sizeof(a));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai=acos(-1.0);
const double E=2.718281828459;
const int mod=20071027;
const int INF=0x3f3f3f3f;

struct node
{
    node *child[26];
    node *fail;
    int sign;
};
node *root;

char word[105];
char text[300005];
int head[300005];

struct ANS
{
    int e;
    int pre;
}edge[2000005];

int sub;

void insert_word(char *s,int len)
{
    node *now=root,*temp;
    int x;
    for(int i=0;s[i];i++)
    {
        x=s[i]-'a';
        if(now->child[x]==NULL)
        {
            temp=new node();
            temp->fail=NULL;
            temp->sign=0;
            memset(temp->child,NULL,sizeof(temp->child));
            now->child[x]=temp;
        }
        now=now->child[x];
    }
    now->sign=len;
}

void build_fail()
{
    queue<node *>q;
    node *now,*temp;
    q.push(root);
    while(!q.empty())
    {
        now=q.front();
        q.pop();
        for(int i=0;i<=25;i++)
        {
            if(now->child[i])
            {
                if(now==root)
                    now->child[i]->fail=root;
                else
                {
                    temp=now->fail;
                    while(temp)
                    {
                        if(temp->child[i])
                        {
                            now->child[i]->fail=temp->child[i];
                            break;
                        }
                        temp=temp->fail;
                    }
                    if(temp==NULL)
                        now->child[i]->fail=root;
                }
                q.push(now->child[i]);
            }
        }
    }
}

void add_edge(int s,int e)
{
    edge[++sub]=ANS{e,head[s]};
    head[s]=sub;
}

void ac_auto(char *s)
{
    node *now=root,*temp;
    int x;
    for(int i=0;s[i];i++)
    {
        x=s[i]-'a';
        while(now!=root&&now->child[x]==NULL)
            now=now->fail;
        now=now->child[x];
        if(now==NULL)
            now=root;
        temp=now;
        while(temp!=root)
        {
            if(temp->sign>0)
                add_edge(i-(temp->sign)+1,i+1);
            temp=temp->fail;
        }
    }
}

void init()
{
    root->fail=NULL;
    root->sign=0;
    memset(root->child,NULL,sizeof(root->child));
}

int main()
{
    int n,s,e,u=0;
    int dp[300005];
    root=new node();
    while(scanf("%s",text)!=EOF)
    {
        init();
        int d=strlen(text);
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",word);
            insert_word(word,strlen(word));
        }
        build_fail();
        for(int i=0;i<d;i++)
        {
            head[i]=-1;
            dp[i]=0;
        }
        dp[d]=1;
        sub=0;
        ac_auto(text);
        for(int i=d-1;i>=0;i--)
        {
            for(int j=head[i];j!=-1;j=edge[j].pre)
            {
                s=i;
                e=edge[j].e;
                dp[s]=(dp[s]+dp[e])%mod;
            }
        }
        printf("Case %d: %d\n",++u,dp[0]);
    }
    return 0;
}

照着大佬思路敲得代码:

///#include<bits/stdc++.h>
///#include<unordered_map>
///#include<unordered_set>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<bitset>
#include<set>
#include<stack>
#include<map>
#include<list>
#include<new>
#include<vector>
#define MT(a,b) memset(a,b,sizeof(a));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai=acos(-1.0);
const double E=2.718281828459;
const int mod=20071027;
const int INF=0x3f3f3f3f;

struct node
{
    node *child[26];
    node *fail;
    int sign;
};

node *root;

char word[105];
char text[300005];
int dp[300005];

void insert_word(char *s)
{
    node *now=root,*temp;
    int x;
    for(int i=0;s[i];i++)
    {
        x=s[i]-'a';
        if(now->child[x]==NULL)
        {
            temp=new node();
            temp->fail=NULL;
            temp->sign=0;
            memset(temp->child,NULL,sizeof(temp->child));
            now->child[x]=temp;
        }
        now=now->child[x];
    }
    now->sign=1;
}

void find_dp(char *s,int d)
{
    int x;
    node *now;
    for(int i=d-1;i>=0;i--)
    {
        now=root;
        for(int j=i;j<=i+100-1&&j<d;j++)
        {
            x=s[j]-'a';
            if(now->child[x]==NULL)
                break;
            now=now->child[x];
            if(now->sign)
                dp[i]=(dp[i]+dp[j+1])%mod;
        }
    }
}

void init()
{
    root->fail=NULL;
    root->sign=0;
    memset(root->child,NULL,sizeof(root->child));
}

int main()
{
    int n,u=0;
    root=new node();
    while(scanf("%s",text)!=EOF)
    {
        init();
        int d=strlen(text);
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",word);
            insert_word(word);
        }
        for(int i=0;i<d;i++)
            dp[i]=0;
        dp[d]=1;
        find_dp(text,d);
        printf("Case %d: %d\n",++u,dp[0]);
    }
    return 0;
}

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值