BZOJ1212: [HNOI2004]L语言

【传送门:BZOJ1212


简要题意:

  给出n个单词,m个母串,输出每个母串最多能用单词覆盖的最长前缀长度(单词与单词之间不可重叠)


题解:

  一开始想着用AC自动机,结果发现fail指针一点用也没有

  就直接建字典树,v[i]表示母串1到i能够被单词覆盖,true表示能覆盖,一开始v[0]=true,然后对于一个母串,从头到尾扫一遍,假设当前扫到i点并且i点能够被单词覆盖,则将i+1到len在字典树中跑,加入能跑到一个单词的结尾,v[k]=true(k表示这个单词的结尾位于母串的位置)

  最后从len往前枚举,找到第一个v为true时,输出当前位置即可

  数据竟然有重复的单词出现,害WA了一次


参考代码:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
struct trie
{
    int s,c[27],fail,d;
    trie()
    {
        s=fail=d=0;
        memset(c,-1,sizeof(c));
    }
}t[210];int cnt;
char a[210],st[1100000];
int v[1100000];
void bt()
{
    int x=0,len=strlen(a+1);
    for(int i=1;i<=len;i++)
    {
        int y=a[i]-'a'+1;
        if(t[x].c[y]==-1) t[x].c[y]=++cnt;
        x=t[x].c[y];
    }
    t[x].s++;
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",a+1);
        bt();
    }
    memset(v,0,sizeof(v));
    for(int i=1;i<=m;i++)
    {
        scanf("%s",st+1);
        int len=strlen(st+1);
        int x=0,ans=0;
        v[0]=i;
        while(x<=len)
        {
            while(v[x]!=i)
            {
                x++;
                if(x==len+1) break;
            }
            int j=0;
            for(int k=x+1;k<=len;k++)
            {
                int y=st[k]-'a'+1;
                if(t[j].c[y]==-1) break;
                else
                {
                    j=t[j].c[y];
                    if(t[j].s>0) v[k]=i;
                }
            }
            x++;
        }
        for(int j=len;j>=1;j--) if(v[j]==i){ans=j;break;}
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2018-01-30 16:23  Star_Feel  阅读(202)  评论(0编辑  收藏  举报