[省选前题目整理][BZOJ 1212][HNOI 2004]L语言(Trie)

142 篇文章 0 订阅
98 篇文章 0 订阅

题目链接

http://www.lydsy.com/JudgeOnline/problem.php?id=1212

思路

不妨设f[i]=true表明当前的文章的前i个字符是合法前缀,那么很容易想到f[i]=true可以推出f[j]=true,其中i+1~j部分是一个单词。

很容易想到把每个单词都放进Trie里面,从0~文章长度遍历f[i],若f[i]=true,把文章从i+1开始的部分放入Trie中匹配,并得到新的f[j]=true的部分,最终我们遍历f数组便可找出最长合法前缀。

代码

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

#define MAXN 1000000
#define MAXM 1000

using namespace std;

struct Trie
{
    int ch[26];
    bool isBadNode;
}node[MAXN];

int nCount=0;

void Insert(char *s)
{
    int p=0,len=strlen(s);
    for(int i=0;i<len;i++)
    {
        if(!node[p].ch[s[i]-'a']) node[p].ch[s[i]-'a']=++nCount;
        p=node[p].ch[s[i]-'a'];
    }
    node[p].isBadNode=true;
}

int n,m;
char str[MAXN],word[MAXM]; //母串与单词串
bool f[MAXN]; //f[i]=true表示1~i这一段是个合法前缀

void ask(char *s,int i) //从str的下标为i处开始匹配
{
    int p=0;
    int t=0; //从str的下标i处开始,在trie中已经匹配了的长度
    while(*s!='\0')
    {
        if(!node[p].ch[*s-'a']) return;
        p=node[p].ch[*s-'a'];
        s++;
        t++;
        if(node[p].isBadNode)
            f[t+i]=true;
    }
    if(node[p].isBadNode) f[t+i]=true;
}

int calc() //计算当前母串str的最长合法前缀
{
    int maxans=0;
    memset(f,false,sizeof(f));
    f[0]=true;
    int len=strlen(str+1);
    for(int i=0;i<=len;i++)
    {
        if(!f[i]) continue;
        maxans=i;
        ask(str+i+1,i);
    }
    return maxans;
}

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",word);
        Insert(word);
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%s",str+1);
        printf("%d\n",calc());
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值