寻宝游戏
题目背景:
分析:思维分析
这道题感觉真的是很厉害的一道题,当时考场上因为的确不知道怎么做,于是就手玩了一下小数据,然后就发现,如果把|看成是0,&看成是1的话,以第n个数之前的符号当成最高位,这样每一种填符号的方案就是一个n位二进制数,然后发现对于可行的符号方案,一定是一段连续的二进制数。并且这些可行解中最小的一个一定是将原来的n个数的相同位置提取出来,从n到1形成的m个二进制数中的一个,而上界是这m个数中的一个减去1,然后又继续找发现了下边界的对应位置一定是结果串中为0的位置,上边界是为1的位置,然后下边界是0当中最大的,上边界是1当中最小的,就这么一步步找规律搞了出来,最后竟然还真的是对的······考虑系统证明一下,首先像我之前说的那样,每一种符号填法形成一个n位二进制数,然后n个原数提取每一位形成m个二进制数,最高位都是第n位,难么我们可以对于每一位分开考虑,显然,|0,或者是&1是没有用的,如果最终位为1,那么最后一个|1一定在最后一个&0之后,反之亦然,所以考虑这在二进制数上的体现,我们从高位向下比较运算符字符串,和形成的当前位字符串,如果两者当前位置相同,则不影响,如果第一个不同的位置,运算符为1,原位置串为0,那么最终这一位结果就是0,否则结果为1,如果两串相同,结果还是为0,那么对于最终位置是1的地方,运算符串显然要比当前位置串小,而如果最终位置是0的话,运算符串显然要大于等于当前位置串,所以我们只需要每一次找出最终位是0的位置串中最大的一个,已经最终位是1的位置串中最小的一个,后减前即为答案,注意判无解的情况即可。
Source:
/*
created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
#include <ctime>
#include <bitset>
inline char read() {
static const int IN_LEN = 1024 * 1024;
static char buf[IN_LEN], *s, *t;
if (s == t) {
t = (s = buf) + fread(buf, 1, IN_LEN, stdin);
if (s == t) return -1;
}
return *s++;
}
/*
template<class T>
inline void R(T &x) {
static char c;
static bool iosig;
for (c = read(), iosig = false; !isdigit(c); c = read()) {
if (c == -1) return ;
if (c == '-') iosig = true;
}
for (x = 0; isdigit(c); c = read())
x = ((x << 2) + x << 1) + (c ^ '0');
if (iosig) x = -x;
}
//*/
const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN];
char *oh = obuf;
inline void write_char(char c) {
if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;
*oh++ = c;
}
template<class T>
inline void W(T x) {
static int buf[30], cnt;
if (x == 0) write_char('0');
else {
if (x < 0) write_char('-'), x = -x;
for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
while (cnt) write_char(buf[cnt--]);
}
}
inline void flush() {
for (int i = 0; i <= 10; ++i) std::cout << obuf[i];
std::cout << '\n';
fwrite(obuf, 1, oh - obuf, stdout), oh = obuf;
}
// /*
template<class T>
inline void R(T &x) {
static char c;
static bool iosig;
for (c = getchar(), iosig = false; !isdigit(c); c = getchar())
if (c == '-') iosig = true;
for (x = 0; isdigit(c); c = getchar())
x = ((x << 2) + x << 1) + (c ^ '0');
if (iosig) x = -x;
}
//*/
const int MAXN = 1000 + 9;
const int MAXM = 5000 + 9;
const int mod = 1000000000 + 7;
int n, m, q;
int sum[MAXM], rk[MAXM], temp[MAXM];
char s[MAXM];
int main() {
//freopen("hunt.in", "r", stdin);
//freopen("hunt.out", "w", stdout);
R(n), R(m), R(q);
int ret = 1;
for (int i = 0; i <= m + 1; ++i) rk[i] = i;
for (int i = 0; i < n; ++i, ret = ret * 2 % mod) {
scanf("%s", s + 1);
for (int j = 1; j <= m; ++j)
sum[j] = (sum[j] + (s[j] - '0') * ret) % mod;
for (int j = 1, h = 0; j <= m; ++j)
if (s[rk[j]] - '0') temp[++h] = rk[j];
for (int j = m, t = m + 1; j >= 1; --j)
if ((s[rk[j]] - '0') == 0) temp[--t] = rk[j];
// for (int j = 1; j <= m; ++j) std::cout << temp[j] << " ";
for (int j = 1; j <= m; ++j) rk[j] = temp[j];
}
// for (int i = 1; i <= m; ++i) std::cout << rk[i] << " ";
// std::cout << '\n';
sum[0] = ret, sum[m + 1] = 0;
while (q--) {
scanf("%s", s + 1);
int p0 = m + 1, p1 = 0;
for (int j = m; j >= 1; --j)
if (s[rk[j]] - '0') {
p1 = j;
break ;
}
for (int j = 1; j <= m; ++j)
if ((s[rk[j]] - '0') == 0) {
p0 = j;
break ;
}
if (p0 <= p1) {
puts("0");
continue ;
}
std::cout << (sum[rk[p1]] - sum[rk[p0]] + mod) % mod << '\n';
}
return 0;
}