hdu 2846(字典树变型)询问子串出现的次数

When you go shopping, you can search in repository for avalible merchandises by the computers and internet. First you give the search system a name about something, then the system responds with the results. Now you are given a lot merchandise names in repository and some queries, and required to simulate the process.
Input
There is only one case. First there is an integer P (1<=P<=10000)representing the number of the merchanidse names in the repository. The next P lines each contain a string (it’s length isn’t beyond 20,and all the letters are lowercase).Then there is an integer Q(1<=Q<=100000) representing the number of the queries. The next Q lines each contains a string(the same limitation as foregoing descriptions) as the searching condition.
Output
For each query, you just output the number of the merchandises, whose names contain the search string as their substrings.
Sample Input
20
ad
ae
af
ag
ah
ai
aj
ak
al
ads
add
ade
adf
adg
adh
adi
adj
adk
adl
aes
5
b
a
d
ad
s
Sample Output
0
20
11
11
2

题意是给出一些模式串,再给出几个询问,询问给出的字符串在多少个模式串中出现
比如字符串abc所含的字串有a,ab,abc,b,bc,c
可用字典树解决,字典树能很好的处理前缀出现的次数,所以可将模式串分解,依次插入
需要注意的是对于同一个模式串的不同子串可能有相同的前缀,为了避免多次计算,可以添加字典树节点的信息,添加num记录最后插入的字符串是第num个模式串的子串

ac自动机t了= =醉了 因为长度比较短,所以直接用字典树暴力插入就好
容易re,开500000我也不知道为啥,我算出来如果不重复的话会有 (1+2…+20)*10000
那么应该是400万,但是肯定会有重复的,因为每一层也就26,所以50万基本就够了

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 500000;
const int CASE_SIZE = 26;

struct Trie
{
    int child[MAXN][CASE_SIZE],value[MAXN],trieN,root;
    int id[MAXN];
    void init()
    {
        trieN=root=0;value[root]=0;
        memset(child[root],-1,sizeof(child[root]));
    }
    int newnode()
    {
        trieN++;value[trieN]=0;
        memset(child[trieN],-1,sizeof(child[trieN]));
        return trieN;
    }
    void insert(char *s,int k)
    {
        int x=root;
        for(int i=0;s[i];i++)
        {
            int d=s[i]-'a';
            if(child[x][d]==-1)
                child[x][d]=newnode();
            x=child[x][d];
            if(id[x]!=k)
            {
                value[x]++;
                id[x]=k;
            }
        }
    }
    int search(char *s)
    {
        int sum=0,x=root;
        for(int i=0;s[i];i++)
        {
            int d=s[i]-'a';
            if(child[x][d]==-1)
                return 0;
            x=child[x][d];
        }
        sum+=value[x];
        return sum;
    }
}trie;


char s[26];
char ss[26];

int main()
{
    int n;
    scanf("%d",&n);
    trie.init();
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s);
        int len=strlen(s);
        for(int j=0;j<len;j++)
            trie.insert(s+j,i);
    }
    int m;
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%s",ss);
        printf("%d\n",trie.search(ss));
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值