【代码超详解】洛谷 P2922 [USACO08DEC]秘密消息Secret Message

本文详细介绍了洛谷P2922问题,即奶牛之间的秘密二进制消息匹配。约翰拦截了部分消息和暗号,需要计算每个暗号能匹配多少条消息。关键在于利用字典树(Trie)进行匹配,考虑到字典树节点的size和end成员统计匹配数。文章提供了两种不同时间复杂度的AC代码实现。
摘要由CSDN通过智能技术生成

一、题目描述

题目描述

Bessie is leading the cows in an attempt to escape! To do this, the cows are sending secret binary messages to each other.

Ever the clever counterspy, Farmer John has intercepted the first b_i (1 <= b_i <= 10,000) bits of each of M (1 <= M <= 50,000) of these secret binary messages.

He has compiled a list of N (1 <= N <= 50,000) partial codewords that he thinks the cows are using. Sadly, he only knows the first c_j (1 <= c_j <= 10,000) bits of codeword j.

For each codeword j, he wants to know how many of the intercepted messages match that codeword (i.e., for codeword j, how many times does a message and the codeword have the same initial bits). Your job is to compute this number.

The total number of bits in the input (i.e., the sum of the b_i and the c_j) will not exceed 500,000.

Memory Limit: 32MB

POINTS: 270

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

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

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

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

输入格式

  • Line 1: Two integers: M and N

  • Lines 2…M+1: Line i+1 describes intercepted code i with an integer b_i followed by b_i space-separated 0’s and 1’s

  • Lines M+2…M+N+1: Line M+j+1 describes codeword j with an integer c_j followed by c_j space-separated 0’s and 1’s

输出格式

  • Lines 1…M: Line j: The number of messages that the jth codeword could match.

输入输出样例

输入 #1

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

1 
3 
1 
1 
2 

说明/提示

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.

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

二、算法分析说明与代码编写指导

观察样例,可以发现待匹配的代码可能比已知代码长也可能比已知代码短。
如果用于查找的代码更短,实现就很简单(字典树的节点保存的信息加上 size 成员,代表该节点的分支数);但是观察样例中要匹配的第四、第五个代码:

5 0 1 0 0 1 
2 1 1 
01001 matches 010: 1 match
11 matches 1 and 110: 2 matches

可以发现当字典树内已有的某些单词是当前输入用于查找的单词的前缀时,这样的情况也要计入总数中。如果只是简单返回所在节点的 size 成员作为答案,是过不了样例的。
放入字典树的已截获信息最多有 M = 50000 条,每一条的长度最多有 10000。如果遍历字典树进行匹配,肯定会超时。
在字典树的节点上已经加入成员 size 用于统计子分支数量的基础上继续改动。
设传入的代码为 w。
如果查找能够进行到 w 的最后一个字符,那么刚才行进到的字典树中的点(即 w 的最后一个字符对应的节点)的一切子分支都包含在答案中。不过,如果前面某些节点实际上已经是存入的代码的结束的话,这些结束的代码也算与 w 匹配。所以我们要将这些属于 w 的前缀的代码都统计到最终答案 ans 内。由于可能含有重复的代码,刻画某个节点是否标记着一个单词的结束的成员变量 end 不能再是 bool 型(否则这题只能对第 1 个点拿 7 分),而要改成整型。每深入一个节点,就要把该节点的 end 加起来。查找完 w 的最后一个字符时,由于最后经过的节点的 end 已经被计入答案,这部分不能重复统计,所以这种情况下最终返回的值是 ans + p->size - p->end。
如果不能查找到 w 的最后一个字符,而是在查找到 w 的中间的某个字符时就已经深入不下去了(即该字符以后的部分不能从当前位置继续检索到),这时候只需要返回已经累计的值 ans 作为结果即可。因为后续不可能再有更长的来自字典树中已储存的代码可以匹配,而且前面的较短的已知代码已经被统计到 ans 中了。

三、AC 代码

版本一(总时间:505 ms):

#include<cstdio>
#include<map>
#pragma warning(disable:4996)
class trie {
   
private:
	struct node {
    std::map<char, node*> next; unsigned end = 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值