zoukankan      html  css  js  c++  java
  • 【bzoj1590】【Usaco2008 Dec】秘密消息Secret Message

    题目描述

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


    输入

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


    输出

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


    样例输入

    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 


    样例输出

    1 
    3 
    1 
    1 
    2 


    题解

    先把信息建成字典树。每个信息的结尾打上标记,并记录以该节点结尾的有多少个。查询的时候,如果是前缀等于信息的情况,那么就返回在字典树上经过的标记的数目,如果是前缀等于密码的情况,那么返回密码的最后一个字符的子树中的标记数。

    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define ll long long
    
    const int maxn=50000*10;
    
    int t[maxn][2],n,m,len,root,tot,cnt[maxn],num[maxn];
    char c[500000+50];
    bool word[maxn];
    
    void insert(char *s,int r){
        root=0;int id;
        for(int i=0;i<r;i++){
            id=s[i]-'0';
            if(!t[root][id]) t[root][id]=++tot;
            cnt[root]++;root=t[root][id];
        }
        word[root]=true;num[root]++;
    }
    
    int find(char *s,int r){
        root=0;int id,ans=0;
        for(int i=0;i<r;i++){
            id=s[i]-'0';
            if(!t[root][id]){
                return ans;
            }
            root=t[root][id];if(word[root]) ans+=num[root];
        }
        return ans+cnt[root];
    }
    
    template<typename T>void read(T& aa){
        char cc; ll ff;aa=0;cc=getchar();ff=1;
        while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
        if(cc=='-') ff=-1,cc=getchar();
        while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
        aa*=ff;
    }
    
    int main(){
        read(m),read(n);
        for(int i=1;i<=m;i++){
            int x,w;
            read(w);for(int i=1;i<=w;i++) read(x),c[i-1]=x+'0';
            insert(c,w);
        }
        for(int i=1;i<=n;i++){
            int x,w;
            read(w);for(int i=1;i<=w;i++) read(x),c[i-1]=x+'0';
            printf("%d
    ",find(c,w));
        }
        return 0;
    }
  • 相关阅读:
    查看linux文件目录的大小和文件夹包含的文件数
    linux下oracle 基本操作
    中宇 设备证书 导入配置
    as5 samba 图形配置
    QQ用户免费申领新型电子密码卡
    GRUB引导下进Linux单用户模式的三种方式
    Iptables 规则 一些简单实例和详细介绍
    Linux上JDK的 安装和卸载 详细 (转)
    Linux/Unix命令之Ethtool (设置千兆网卡速度及模式)
    oracle 下 创建数据库和用户界面操作 和sql 语句 下的创建方法
  • 原文地址:https://www.cnblogs.com/rlddd/p/9785450.html
Copyright © 2011-2022 走看看