首页 > 其他 > 详细

【洛谷P2922】Secret Message

时间:2019-05-07 11:53:37      阅读:147      评论:0      收藏:0      [点我收藏+]

题目大意:给定 N 个字符串组成的字典,有 M 个询问,每次给定一个字符串,求字典中有多少个单词为给定字符串的前缀或前缀是给定的字符串。

题解:在 trie 上维护一个 tag 表示有多少字符串以当前字符串为前缀,ed 表示从该节点到根节点之间为一个字符串。
对于给定的字符串,在 trie 中顺序查找,在匹配的过程中累加经过节点的 ed 标记,表示有多少字符串为给定字符串的前缀。若匹配成功,则答案累加 tag 标记并减去最后一个节点的 ed 标记,防止重复计算。若匹配失败,只需输出记录的 ed 之和即可。

代码如下

#include <bits/stdc++.h>
using namespace std;
const int maxn=5e5+10;

int trie[maxn][2],tot=1,tag[maxn],ed[maxn];
int m,n,len,s[10010];

void insert(int *ss){
    int now=1;
    for(int i=1;i<=len;i++){
        int ch=ss[i];
        if(!trie[now][ch])trie[now][ch]=++tot;
        now=trie[now][ch],++tag[now];
    }
    ++ed[now];
}
void query(int *ss){
    int now=1,ret=0;
    for(int i=1;i<=len;i++){
        int ch=ss[i];
        if(!trie[now][ch]){
            printf("%d\n",ret);
            return;
        }
        now=trie[now][ch];
        ret+=ed[now];
    }
    printf("%d\n",ret+tag[now]-ed[now]);
}

int main(){
    scanf("%d%d",&m,&n);
    for(int i=1;i<=m;i++){
        scanf("%d",&len);
        for(int j=1;j<=len;j++)scanf("%d",&s[j]);
        insert(s);
    }
    for(int i=1;i<=n;i++){
        scanf("%d",&len);
        for(int j=1;j<=len;j++)scanf("%d",&s[j]);
        query(s);
    }
    return 0;
}

【洛谷P2922】Secret Message

原文:https://www.cnblogs.com/wzj-xhjbk/p/10824463.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!