HDU 6096 String 字典树数组建树

10 篇文章 0 订阅

题目链接:HDU6096

String

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 996    Accepted Submission(s): 325


Problem Description
Bob has a dictionary with N words in it.
Now there is a list of words in which the middle part of the word has continuous letters disappeared. The middle part does not include the first and last character.
We only know the prefix and suffix of each word, and the number of characters missing is uncertain, it could be 0. But the prefix and suffix of each word can not overlap.
For each word in the list, Bob wants to determine which word is in the dictionary by prefix and suffix.
There are probably many answers. You just have to figure out how many words may be the answer.
 

Input
The first line of the input gives the number of test cases T; T test cases follow.
Each test case contains two integer N and Q, The number of words in the dictionary, and the number of words in the list.
Next N line, each line has a string Wi, represents the ith word in the dictionary ( 0<|Wi|100000 )
Next Q line, each line has two string Pi , Si, represents the prefix and suffix of the ith word in the list ( 0<|Pi|,|Si|100000,0<|Pi|+|Si|100000 )
All of the above characters are lowercase letters.
The dictionary does not contain the same words.

Limits
T5
0<N,Q100000
Si+Pi500000
Wi500000
 

Output
For each test case, output Q lines, an integer per line, represents the answer to each word in the list.
 

Sample Input
  
  
1 4 4 aba cde acdefa cdef a a cd ef ac a ce f
 

Sample Output
  
  
2 1 1 0
 

题意:

给出一堆单词,然后m次查询,每次给出前缀和后缀,询问有几个单词满足条件。

题目分析:

AC自动机的做法:把每个单词的后缀放到前面然后在中间隔一个特殊字符,然后同样处理查询字符串,跑一遍ac自动机即可。

字典树做法:前缀一个字母后缀一个交替的放入一个新字符串里,然后录入字典树,查询时同样处理,然后如果不够的话用特殊字符代替。查询类似广搜,然后不带*的就1条路径,带*的就全录进去(话说复杂度不会爆炸吗)。当时赛场上想着是建立26*26的二维数组同时录入前缀和后缀,然后考虑查询最坏情况可能爆炸就没写完,这么看还是可以试一试的,毕竟大同小异,一个是双倍长度,一个是多26倍的节点。

//
//  main.cpp
//  HDU6096 String
//
//  Created by teddywang on 2017/8/14.
//  Copyright © 2017年 teddywang. All rights reserved.
//

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int N=2222222;
int n,q;
char s[N],t[N],st[N];
struct node{
    int L,root,net[N][26],ed[N];
    vector<int>G[N];
    int newnode()
    {
        for(int i=0;i<26;i++)
            net[L][i]=-1;
        ed[L]=0;
        return L++;
    }
    void init()
    {
        L=0;
        for(int i=0;i<N;i++)
            G[i].clear();
        root=newnode();
    }
    void build(char *s,int l)
    {
        int len=strlen(s);
        int now=root;
        for(int i=0;i<len;i++)
        {
            int buf=s[i]-'a';
            if(net[now][buf]==-1)
            {
                net[now][buf]=newnode();
            }
            now=net[now][buf];
            G[now].push_back(l);
            ed[now]++;
        }
    }
    void dfs(int x)
    {
        sort(G[x].begin(),G[x].end());
        for(int i=0;i<26;i++)
        {
            if(net[x][i]!=-1)
            {
                dfs(net[x][i]);
            }
        }
    }
};
node trie;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        trie.init();
        scanf("%d%d",&n,&q);
        for(int i=0;i<n;i++)
        {
            scanf("%s",s);
            int len=strlen(s);
            for(int j=0;j<len;j++)
            {
                st[j*2]=s[j];
                st[j*2+1]=s[len-1-j];
            }
            st[2*len]='\0';
            trie.build(st, len);
        }
        trie.dfs(0);
        for(int i=0;i<q;i++)
        {
            scanf("%s%s",s,t);
            int ls=strlen(s);
            int lt=strlen(t);
            int l=ls+lt;
            int ll=max(ls,lt);
            for(int j=0;j<ll;j++)
            {
                st[j*2]=j<ls?s[j]:'*';
                st[j*2+1]=j<lt?t[lt-1-j]:'*';
            }
            ll*=2;
            st[ll]='\0';
            queue<int> q[2];
            int tmp=0;
            q[0].push(0);
            int ans=0;
            for(int j=0;j<ll;j++)
            {
                tmp=1-tmp;
                int buf=st[j]-'a';
                while(!q[1-tmp].empty())
                {
                    int now=q[1-tmp].front();
                    q[1-tmp].pop();
                    if(st[j]=='*')
                    {
                        for(int k=0;k<26;k++)
                        {
                            if(trie.net[now][k]!=-1)
                                q[tmp].push(trie.net[now][k]);
                        }
                    }
                    else
                    {
                        if(trie.net[now][buf]!=-1)
                            q[tmp].push(trie.net[now][buf]);
                    }
                }
            }
            while(!q[tmp].empty())
            {
                int now=q[tmp].front();
                q[tmp].pop();
                int buf=lower_bound(trie.G[now].begin(), trie.G[now].end(),l)-trie.G[now].begin();
                ans-=buf;
                ans+=trie.ed[now];
                
            }
            printf("%d\n",ans);
        }
    }
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值