Problem

Description

某大学每年都会有一次 \(Mystery\ Hunt\) 的活动,玩家需要根据设置的线索解谜,找到宝藏的位置,前一年获胜的队伍可以获得这一年出题的机会。

作为新生的你,对这个活动非常感兴趣。你每天都要从西向东经过教学楼一条很长的走廊,这条走廊是如此的长,以至于它被人戏称为 \(Infinite\ Corridor\) 。一次,你经过这条走廊的时候,注意到在走廊的墙壁上隐藏着 \(n\) 个等长的二进制的数字,长度均为 \(m\) 。你从西向东将这些数字记录了下来,形成一个含有 \(n\) 个数的二进制数组 \(a_1, a_​2 \cdots, a_​n\) 。

很快,在最新的一期 \(Voo\ Doo\) 杂志上,你发现了 \(q\) 个长度也为 \(m\) 的二进制串 \(r_1, r_​2, \cdots, r_​q\) 。

聪明的你很快发现了这些数字的含义。

保持数组 \(a_1, a_​2 \cdots, a_n\) 的元素顺序不变,你可以在它们之间插入 \(\land\)(按位与运算)或者 \(\vee\)(按位或运算)两种二进制运算符。例如: \(11011 \land 00111 = 00011,11011 \vee 00111 = 11111\) 。

你需要插入恰好 \(n\) 个运算符,相邻两个数之间恰好一个,在第一个数的左边还有一个。如果我们在第一个运算符的左边补入一个 \(0\) ,这就形成了一个运算式,我们可以计算它的值。与往常一样,运算顺序是从左往右。有趣的是,出题人已经告诉你这个值的可能的集合—— \(Voo Doo\) 杂志里的那一些二进制数 \(r_1, r_​2, \cdots, r_q\) ,而解谜的方法,就是对 \(r_1, r_​2, \cdots, r_q\) 中的每一个值 \(r_i\) ,分别计算出有多少种方法填入这 \(\mathbf{n}\) 个运算符,使得这个运算式的值是 \(r_i\) 。

然而,\(Infinite\ Corridor\) 真的很长,这意味着数据范围可能非常大。因此,答案也可能非常大,但是你发现由于谜题的特殊性,你只需要求答案模\(1000000007(10 ^ 9 + 7\) , 一个质数)的值。

Input Format

第一行三个数\(n,m,q\),含义如题所述。

接下来\(n\)行,其中第\(i\)行有一个长度为\(m\)的二进制串,左边是最高位,表示\(a_i\)。

接下来\(q\)行,其中第\(i\)行有一个长度为\(m\)的二进制串,左边是最高位,表示\(r_i\)。

Output Format

输出\(q\)行,每行一个数,其中第\(i\)行表示对应于\(r_i\)的答案。

Sample

Input 1

  1. 5 5 1
  2. 01110
  3. 11011
  4. 10000
  5. 01010
  6. 00100
  7. 00100

Output 1

  1. 6

Input 2

  1. 10 10 3
  2. 0100011011
  3. 0110100101
  4. 1100010100
  5. 0111000110
  6. 1100011110
  7. 0001110100
  8. 0001101110
  9. 0110100001
  10. 1110001010
  11. 0010011101
  12. 0110011111
  13. 1101001010
  14. 0010001001

Output2

  1. 69
  2. 0
  3. 5

Explanation

Explanation for Input 1

有以下且仅有以下六个运算式的值是\(00100_{2}\):(下标2表示被标识的数是二进制数)

\(0 \land \ 01110_{2} \land \ 11011_{2} \vee {\ 10000}_{2}{\ \land 01010}_{2}{\ \vee 00100}_{2}\)

\(0 \vee \ 01110_{2}\ {\vee 11011}_{2}\ \land {\ 10000}_{2}{\ \ \land 01010}_{2}{\ \vee 00100}_{2}\)

\(0 \land \ 01110_{2}\ {\vee 11011}_{2} \land {\ 10000}_{2}{\ \land 01010}_{2}{\ \vee 00100}_{2}\)

\(0 \vee \ 01110_{2} \land \ 11011_{2} \land {\ 10000}_{2}{\land \ 01010}_{2}{\ \vee 00100}_{2}\)

\(0 \land \ 01110_{2}\ {\land 11011}_{2} \land {\ 10000}_{2}{\ \land 01010}_{2}{\ \vee 00100}_{2}\)

\(0 \vee \ 01110_{2}\ \vee 11011_{2} \vee {\ 10000}_{2}{\ \ \vee 01010}_{2}{\ \land 00100}_{2}\)

Range

对于 \(10\%\) 的数据,\(n \leq 20, m \leq 30, \ q = 1\)

对于另外 \(20\%\) 的数据,\(n \leq 1000, m \leq 16\)

对于另外 \(40\%\) 的数据,\(n \leq 500, m \leq 1000\)

对于 \(100\%\) 的数据,\(1 \leq n \leq 1000, \ 1 \leq m \leq 5000, \ 1 \leq q \leq 1000\)

Algorithm

基数排序可能算一个???

Mentality

这个题看起来超级吓人 \(......\) 难度看起来确实挺大的样子。

但是我们应该冷静思考,先看看数据范围,\(10^3\) 左右,这大概就只有 \(O(nm)\) 的复杂度才能过了,最多带点小常数,连 \(log\) 都带不起。

辣么怎么办呢?冷静分析的话,我们决定单独来按位思考,想想每个二进制数的某一位经过运算的结果。

首先,我们发现每一位的运算符只有四种情况:

\(\&0,\&1,|0,|1\)

而我们需要学会发现这四种情况里没啥用的情况,那就是 \(\&1\) 和 \(|0\) 这两个运算,它们对于运算结果没有任何影响。那么有影响的就只剩下了两种情况:当前位为 \(1\) 的时候,我们插入 \(|\) 符号将会使得结果必定为 \(1\) ,否则结果不变;当前位为 \(0\) 的时候,我们插入 \(\&\) 符号会使得结果必定为 \(0\) 。否则结果不变。

那么我们需要做的就变得很简单了:如果询问中这一位为 \(1\) ,那么我们必需确保最后一个有效的操作 (\(\&0\) 和 \(|1\)) 为 \(|1\) ,如果这一位为 \(0\) ,则必须确保最后一个有效操作为 \(\&0\) 或者没有有效操作 (初始值为 \(0\)) 。

接着就是一个异常巧妙的转化了:

由于我们发现 \(\&1\) 和 \(|0\) 这两个东西对结果没有任何影响,那么我们开开脑洞:我们认为 \(\&\) 和 \(1\) 是等价的,\(|\) 和 \(0\) 是等价的!

然后脑洞不要停,我们将当前位每个数前插入运算符构成一个 \(01\) 串来看,设这个串为 \(opt\) ,其中的 \(\&\) 运算代表的值就直接设为 \(1\) ,\(|\) 运算代表的值直接设为 \(0\) 。那么我们发现,将 \(opt\) 与当前位的数构成的 \(01\) 串对其后,如果数为 \(1\) ,而 \(opt\) 的相同位置为 \(1\) 的话,这一位上的二进制值就是相等的,这符合我们等价的脑洞。

接着,我们会异常惊喜地发现一件事情,根据之前的说法,如果我们要使运算的结果为 \(1\) ,那么最后一个有效的操作必须为 \(|1\) ,则对于最后一个有效操作的位置往后,都必须是等价操作 (也即无效操作) 。

而最后一个要求结果为 \(1\) 的有效操作位置,我们必须填入 \(|\) ,也就是在 \(opt\) 串的相同位置,我们的值为 \(0\) ,而我们此位置往后的位置又全部相等!

想到了什么吗?对!如果我们将 \(n\) 个数的当前位提出来,从后往前构成一个二进制数的话,我们必须大于当前 \(opt\) 串代表的二进制数!

举个例子:

这是 \(n\) 个数的当前位:\(1010111\)

若要使结果为 \(0\) ,假设我们最后一个有效操作在第 \(5\) 位,那么最后两位的运算操作都必须为 \(\&\) 运算,也就是 \(1\) ,那么我们的操作串如下,\(.\) 代表既可以填 \(1\) 有可以填 \(0\) 。

\(opt:\ ....011\)

当前位倒过来之后为:\(1110101\)

操作串倒过来之后为:\(opt:\ 110....\)

\(opt<\) \(n\) 个数当前位构成的串

总结陈词,我们设 \(b_i\) 为 \(n\) 个数的第 \(i\) 位提出来再倒过来组成的二进制数,那么若 \(r_i\) 的第 \(j\) 位为 \(1\) ,我们必须保证我们的操作串 \(opt< b_j\) ,而我们已经证明过了,这是必然要求,那么换而言之,如果 \(opt\ge b_j\) ,这一位的结果就必定为 \(0\) 。

于是我们的题目变成了好玩的比大小游戏,我们只需要根据 \(m\) 个和 \(opt\) 有关的不等式得出结果就好了 \(hhhg\) 。

那这题的做法出来了!

先预处理出 \(b\) 数组并排序。

对于当前询问,我们找到满足 \(r_i=0\) 的最大 \(b_i\) ,设当前 \(i\) 为 \(L\) ,满足 \(r_i=1\) 的最小 \(b_i\) ,设当前 \(i\) 为 \(R\) ,那么最后的答案肯定就是 \(b_R-b_L\) 啊 \(hhhhh\) 。

当然注意当 \(L>R\) 输出 \(0\) 。

您问我怎么排序?当然是基数排序啊!常数只有 \(2\) 的 \(O(nm)\) 排序算法。

但是如果您不知道基数排序我就没办法了 \(QwQ\) ,学一下吧,挺简单的。

Code

  1. #include <cstdio>
  2. #include <iostream>
  3. using namespace std;
  4. const int mod = 1e9 + 7;
  5. int n, m, Q, tag[2], ra[5002], rb[5002], num[5001], mi[1002], t[5002];
  6. char s[5002], q[5002];
  7. void Mod(int &x) { x = (x % mod + mod) % mod; }
  8. int main() {
  9. cin >> n >> m >> Q;
  10. mi[1] = 1;
  11. for (int i = 2; i <= n + 1; i++)
  12. mi[i] = (mi[i - 1] << 1) % mod; //预处理一下幂
  13. for (int i = 1; i <= m; i++) ra[i] = i; //排名
  14. for (int i = 1; i <= n; i++) {
  15. scanf("%s", s + 1);
  16. tag[0] = 0, tag[1] = m; //基排的桶
  17. for (int j = 1; j <= m; j++) {
  18. Mod(num[j] += s[j] == '1' ? mi[i] : 0); //处理 b 数组的值
  19. if (s[j] == '0') tag[0]++;
  20. }
  21. for (int j = m; j >= 1; j--)
  22. rb[tag[s[ra[j]] - '0']--] = ra[j]; //获取下一轮排名
  23. swap(ra, rb); //更新排名
  24. }
  25. ra[m + 1] = m + 1;
  26. num[m + 1] =
  27. mi[n +
  28. 1]; //因为如果要求的结果中没有 1 ,那么操作串大小上限就是 2^n-1 了。
  29. while (Q--) {
  30. scanf("%s", q + 1);
  31. int l = 0, r = m + 1;
  32. for (int i = 1; i <= m; i++)
  33. if (q[ra[i]] == '1') {
  34. r = i;
  35. break;
  36. } //找到最小的
  37. for (int i = m; i >= 1; i--)
  38. if (q[ra[i]] == '0') {
  39. l = i;
  40. break;
  41. } //找到最大的
  42. if (l > r)
  43. cout << "0\n";
  44. else
  45. printf("%d\n", ((num[ra[r]] - num[ra[l]]) % mod + mod) % mod);
  46. }
  47. }

【HNOI 2018】寻宝游戏的更多相关文章

  1. [HNOI 2018]寻宝游戏

    Description 题库链接 给出 \(n\) 个 \(m\) 位的二进制数,在每一个二进制数间插入一个 & 或 | ,第 \(0\) 个数为 \(0\) , \(0,1\) 间也要插入符 ...

  2. [Bzoj5285][洛谷P4424][HNOI/AHOI2018]寻宝游戏(bitset)

    P4424 [HNOI/AHOI2018]寻宝游戏 某大学每年都会有一次Mystery Hunt的活动,玩家需要根据设置的线索解谜,找到宝藏的位置,前一年获胜的队伍可以获得这一年出题的机会. 作为新生 ...

  3. 【HNOI 2018】游戏

    Problem Description 一次小 \(G\) 和小 \(H\) 在玩寻宝游戏,有 \(n\) 个房间排成一列,编号为 \(1,2,-,n\),相邻房间之间都有 \(1\) 道门.其中一部 ...

  4. 洛谷P4424 [HNOI/AHOI2018]寻宝游戏(思维题)

    题意 题目链接 Sol 神仙题Orz Orz zbq爆搜70.. 考虑"与"和"或"的性质 \(0 \& 0 = 0, 1 \& 0 = 0\) ...

  5. BZOJ5285 & 洛谷4424 & UOJ384:[HNOI/AHOI2018]寻宝游戏——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=5285 https://www.luogu.org/problemnew/show/P4424 ht ...

  6. [HNOI/AHOI2018]寻宝游戏

    题目大意: $n(n\le1000)$个$m(m\le5000)$位的二进制数,第$0$个数为$0$.用$\wedge$和$\vee$将这些数连接起来.$q(q\le1000)$次询问,每次给定一个$ ...

  7. 【洛谷4424】[HNOI/AHOI2018] 寻宝游戏(位运算思维题)

    点此看题面 大致题意: 给你\(n\)个\(m\)位二进制数.每组询问给你一个\(m\)位二进制数,要求你从\(0\)开始,依次对于这\(n\)个数进行\(and\)或\(or\)操作,问有多少种方案 ...

  8. P3320 [SDOI2015]寻宝游戏 解题报告

    P3320 [SDOI2015]寻宝游戏 题目描述 小B最近正在玩一个寻宝游戏,这个游戏的地图中有\(N\)个村庄和\(N-1\)条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以 ...

  9. [BZOJ3991][SDOI2015]寻宝游戏

    [BZOJ3991][SDOI2015]寻宝游戏 试题描述 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择 ...

  10. 【BZOJ】【3991】【SDOI2015】寻宝游戏

    dfs序 我哭啊……这题在考试的时候(我不是山东的,CH大法吼)没想出来……只写了50分的暴力QAQ 而且苦逼的写的比正解还长……我骗点分容易吗QAQ 骗分做法: 1.$n,m\leq 1000$: ...

随机推荐

  1. oracle 11g R2(静默安装)

    参考博客地址:https://blog.csdn.net/jameshadoop/article/details/48223645 https://www.abcdocker.com/abcdocke ...

  2. TCP、UDP详解与抓包工具使用

    参考:https://www.cnblogs.com/HPAHPA/p/7737641.html TCP.UDP详解 1.传输层存在的必要性 由于网络层的分组传输是不可靠的,无法了解数据到达终点的时间 ...

  3. 异常HTTP Status 500 - Illegal access to constructor, is it public? java.lang.IllegalAccessException: Class com.opensymphony.xwork2.ObjectFactory can not access a member of class action.CoreAction with

    Exception report message Illegal access to constructor, is it public? description The server encount ...

  4. HTML、CSS知识点,面试开发都会需要--No.6 设置背景

    No.6 设置背景 1.background (1)如何设置背景:背景可通过color.image.gradient渐变或者组合方法设置. (2)background-color:颜色格式可以是十六进 ...

  5. python re(正则表达式模块)学习

    一.简介 正则表达式本身是一种小型的.高度专业化的编程语言,而在python中,通过内嵌集成re模块,程序媛们可以直接调用来实现正则匹配.正则表达式模式被编译成一系列的字节码,然后由用C编写的匹配引擎 ...

  6. day12 十二、开放封闭、装饰器

    一.nonlocal关键词 # global # num = # def fn(): # global num # L>G 将局部的名字与全局统一 # num = # fn() # print( ...

  7. UCloud首尔机房整体热迁移是这样炼成的

    小结: 1.把两个机房在逻辑上变成一个机房: 2.新老机房的后端服务使用同一套 ZooKeeper,但是配置的却是不同的 IP: 3.UCloud内部服务所使用的数据库服务为MySQL, 内部MySQ ...

  8. 基于 redis 的分布式锁实现 Distributed locks with Redis debug 排查错误

    小结: 1. 锁的实现方式,按照应用的实现架构,可能会有以下几种类型: 如果处理程序是单进程多线程的,在 python下,就可以使用 threading 模块的 Lock 对象来限制对共享变量的同步访 ...

  9. JMeter学习-041-响应数据中文乱码解决方法

    华夏子孙,中文为母语.因而在接口测试过程中,响应数据含有中文是再也正常不过的事情.同时,初学JMeter的童鞋,经常会遇到响应数据中中文乱码的问题. 本文中提供两种方式的修正方法,仅供大家参考,谢谢. ...

  10. 台式电脑、笔记本快捷选择启动项Boot 快捷键大全

    我们在安装系统时,会去设置电脑是从硬盘启动.U盘启动.光驱启动.网卡启动. 一般设置的方法有两种:一种是进BIOS主板菜单设置启动项顺序:另一种就是我在这里要介绍的快捷选择启动项. 以下是网友整理的各 ...