[trie]秘密消息

题目描述

贝茜正在领导奶牛们逃跑.为了联络,奶牛们互相发送秘密信息.

信息是二进制的,共有M(1≤M≤50000)条.反间谍能力很强的约翰已经部分拦截了这些信息,知道了第i条二进制信息的前bi(l《bi≤10000)位.他同时知道,奶牛使用N(1≤N≤50000)条密码.但是,他仅仅了解第J条密码的前cj(1≤cj≤10000)位.

对于每条密码J,他想知道有多少截得的信息能够和它匹配.也就是说,有多少信息和这条密码有着相同的前缀.当然,这个前缀长度必须等于密码和那条信息长度的较小者.

在输入文件中,位的总数(即∑Bi+∑Ci)不会超过500000.

输入输出格式

输入格式

第一行两个整数m,n
接下来m行每行第一个为bi,后接bi个0或1表示信息
接下来n行每行第一个为ci,后接ci个0或1表示密码

输出格式

共n行,每行一个正整数表示对于每个密码,和其他信息的公共前缀个数

分析

其实很容易想到字典树,因为要匹配公共前缀嘛
容易想到加密码范围内的信息结尾个数和密码结尾的最大公共前缀个数
(有点小坑就是如果信息和密码同样长度,忽略这个信息的结尾最大公共前缀个数)

#include <iostream>
#include <cstdio>
#include <cstring>
#define rep(i,a,b) for (i=a;i<=b;i++)
using namespace std;
int root=0,cnt,m;
int f[500001][2],s[500001],b[500001];
void inse(int p)
{
    int r=root,i,x;
    for (i=1;i<=p;i++)
    {
        scanf("%d",&x);
        if (!f[r][x]) f[r][x]=++cnt;
        r=f[r][x];
        s[r]++;
    }
    b[r]++;s[r]--;
}
int sear(int p,char *a)
{
    int r=root,i,x,cnt=0;
    for (i=0;i<=p-1;i++)
    {
        x=a[i]-'0';
        if (!f[r][x]) return cnt;
        r=f[r][x];
        cnt+=b[r];
    }
    return cnt+s[r];
}
void init()
{
    int i,n,p;
    scanf("%d%d",&n,&m);
    rep(i,1,n)
    {
        scanf("%d",&p);
        inse(p);
    }
}
void print()
{
    int i,j,p,q;
    char a[10001];
    rep(i,1,m)
    {
        scanf("%d",&p);
        rep(j,0,p-1)
        {
            scanf("%d",&q);
            a[j]=q+48;
        }
        printf("%d\n",sear(p,a));
    }
}
int main()
{
    init();
    print();
}

猜你喜欢

转载自blog.csdn.net/SSL_QYH0Ice/article/details/80077861
今日推荐