洛谷 P4424 [HNOI/AHOI2018]寻宝游戏

视最后一个数为最高位,把操作符视作 01 串(& \(\rightarrow\) 1| \(\rightarrow\) 0),记做 \(opt\)
视最后一个数为最高位,把 \(n\) 个长度为 \(m\) 的 01 串按位拆成 \(m\) 个长度为 \(n\) 的 01 串,记做 \(x_i\)
发现第 \(i\) 位为 \(0\),当且仅当 \(opt \geq x_i\);第 \(i\) 位为 \(1\),当且仅当 \(opt \le x_i\)
\(m\) 个约束合并,就可以得到形如 \(l \leq opt \le r\) 的不等式,答案即为 \(r - l\)

#pragma GCC optimize(2)
#include <cstdio>
#include <cstring>

const int MOD = 1e9 + 7, MAXN = 1e3 + 19, MAXM = 5e3 + 19;

int n, m, q;
char str[MAXM];
bool bit[MAXM][MAXN];
int l, r, ans;

int p[MAXN];

bool less(bool* a, bool* b){
	for(int i = n; i >= 1; --i)
		if(a[i] != b[i])
			return a[i] < b[i];
	return false;
}

bool greater(bool* a, bool* b){
	for(int i = n; i >= 1; --i)
		if(a[i] != b[i])
			return a[i] > b[i];
	return false;
}

bool greater_equal(bool* a, bool* b){
	for(int i = n; i >= 1; --i)
		if(a[i] != b[i])
			return a[i] > b[i];
	return true;
}

int main(){
	std::scanf("%d%d%d", &n, &m, &q);
	p[0] = 1;
	for(int i = 1; i < n; ++i)
		p[i] = (p[i - 1] << 1) % MOD;
	for(int i = 1; i <= n; ++i){
		std::scanf("%s", str + 1);
		for(int j = 1; j <= m; ++j)
			bit[j][i] = str[j] == '1';
	}
	std::memset(bit[m + 1], 0, sizeof bit[m + 1]);
	std::memset(bit[m + 2], 0xff, sizeof bit[m + 1]);
	while(q--){
		std::scanf("%s", str + 1);
		l = m + 1, r = m + 2, ans = 1;
		for(int i = 1; i <= m; ++i){
			if(str[i] == '0')
				less(bit[l], bit[i]) ? l = i : 0;
			else if(str[i] == '1'){
				greater(bit[r], bit[i]) ? r = i : 0;
				ans = 0;
			}
		}
		if(greater_equal(bit[l], bit[r])){
			std::puts("0");
			continue;
		}
		for(int i = 1; i <= n; ++i){
			if(bit[l][i])
				ans = (ans - p[i - 1]) % MOD;
			if(bit[r][i])
				ans = (ans + p[i - 1]) % MOD;
		}
		ans = (ans + MOD) % MOD;
		std::printf("%d\n", ans);
	}
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/natsuka/p/12792556.html