洛谷P2922 [USACO008DEC] 秘密消息Secret Message [Trie树]

  洛谷传送门BZOJ传送门

秘密消息Secret Message

Description

    贝茜正在领导奶牛们逃跑.为了联络,奶牛们互相发送秘密信息.
    信息是二进制的,共有M(1≤M≤50000)条.反间谍能力很强的约翰已经部分拦截了这些信息,知道了第i条二进制信息的前bi(l《bi≤10000)位.他同时知道,奶牛使用N(1≤N≤50000)条密码.但是,他仅仅了解第J条密码的前cj(1≤cj≤10000)位.
    对于每条密码J,他想知道有多少截得的信息能够和它匹配.也就是说,有多少信息和这条密码有着相同的前缀.当然,这个前缀长度必须等于密码和那条信息长度的较小者.
    在输入文件中,位的总数(即∑Bi+∑Ci)不会超过500000.

Input

    第1行输入N和M,之后N行描述秘密信息,之后M行描述密码.每行先输入一个整数表示信息或密码的长度,之后输入这个信息或密码.所有数字之间都用空格隔开.

Output

 
    共M行,输出每条密码的匹配信息数.

Sample Input

4 5
3 0 1 0
1 1
3 1 0 0
3 1 1 0
1 0
1 1
2 0 1
5 0 1 0 0 1
2 1 1

INPUT DETAILS:

Four messages; five codewords.
The intercepted messages start with 010, 1, 100, and 110.
The possible codewords start with 0, 1, 01, 01001, and 11.


Sample Output

1
3
1
1
2

HINT

 

0 matches only 010: 1 match 1 matches 1, 100, and 110: 3 matches 01 matches only 010: 1 match 01001 matches 010: 1 match 11 matches 1 and 110: 2 matches


  分析:

  并不难的一道$Trie$树。

  题目中的前缀长度为信息串与密码串中较短的一个,那么我们可以这么做,在$Trie$树的每一个节点记录一个$value$,表示该节点由多少个单词使用过,在每一个信息串的末尾记录一个$id$,表示该单词共出现过几次。然后比较的时候统计经过的所有完整的单词数,然后如果扫完了整个密码串,我们需要判断一下当前扫到的位置是否是末端点,如果不是还需要把包含该节点但不在该节点处结尾的单词数统计一下。注意细节即可。(说的比较绕,看不懂就直接看代码吧)

  Code:

//It is made by HolseLee on 12th Aug 2018
//luogu.org P2922 
#include<bits/stdc++.h>
using namespace std;

const int N=5e5+7;
int n,m,tot,s[N];
struct Node{
    int nx[2],val,id;
}t[N];
struct Trie{
    void ins()
    {
        int root=0;
        for(int i=1;i<=s[0];++i){
            if(!t[root].nx[s[i]]){
                t[root].nx[s[i]]=++tot;
                t[t[root].nx[s[i]]].val=0;
            }
            root=t[root].nx[s[i]];
            t[root].val++;
            if(i==s[0])t[root].id++;
        }
    }

    int quary()
    {
        int root=0,ret=0;bool flag=false;
        for(int i=1;i<=s[0];++i){
            root=t[root].nx[s[i]];
            if(!root){
                flag=true;break;
            }
            ret+=t[root].id;
        }
        if(!flag)ret+=(t[root].val-t[root].id);
        return ret;
    }
}T;

inline int read()
{
    char ch=getchar();int num=0;bool flag=false;
    while(ch<'0'||ch>'9'){if(ch=='-')flag=true;ch=getchar();}
    while(ch>='0'&&ch<='9'){num=num*10+ch-'0';ch=getchar();}
    return flag?-num:num;
}

int main()
{
    n=read();m=read();
    t[0].val=0;
    for(int i=1;i<=n;++i){
        s[0]=read();
        for(int j=1;j<=s[0];++j)s[j]=read();
        T.ins();
    }
    for(int i=1;i<=m;++i){
        s[0]=read();
        for(int j=1;j<=s[0];++j)s[j]=read();
        printf("%d\n",T.quary());
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/cytus/p/9464455.html
今日推荐