#UOJ 384 luoguP4424 HNOI2018 寻宝游戏 思维题

版权声明:_ https://blog.csdn.net/lunch__/article/details/82824338

题意

  • 给你 n n 01 01 串, q q 次询问,每次询问一个 01 01 串,问在每个 01 01 串前添加&或|,有多少种方案使得最后的结果为询问的串,对 1 e 9 + 7 1e9 + 7 取模 n < = 1 e 3 , q < = 1 e 3 n <= 1e3, q <= 1e3

这个题看了好久题解才会做… 做题要心静啊

首先考虑按位处理 对于其中的每一位我们提出来看

首先我们观察一下位运算的一些性质

1   a n d   0 = 0 , 0   a n d   0 = 0 1 \ and\ 0 = 0, 0 \ and \ 0 = 0

这说明如果 a n d   0 and \ 0 的话这位的值就和前面的没关系 o r   1 or\ 1 同理

1   a n d   1 = 1 , 0   a n d   1 = 0 1\ and\ 1 = 1, 0\ and\ 1 = 0

这说明如果 a n d   1 and\ 1 的话这位的值就和当前位没关系 o r   0 or\ 0 同理

那么我们把运算符变成 01 01 序列, o r = 0 , a n d = 1 or = 0, and =1

那么如果某一位上的值是 1 1 的话

那么它最后一个 o r   1 or\ 1 一定在最后一个 a n d   0 and\ 0 前面

o r or 0 0 , a n d and 1 1 转化一下就是

运算符序列的字典序小于当前序列

同理那一位是 0 0 就是字典序大于等于当前序列

那么这个题目就转化成了一个求字符串字典序的题

直接用 s t d   s t r i n g std\ string 就好了 有些细节要注意

注意下询问全 0 0 序列,因为我们的区间 L , R L, R 是前闭后开

但是对于全 0 0 序列来说全部用 1 1 操作也是合法的

然后就做完了 复杂度 O ( q ( n + m ) l o g n ) O(q(n + m)logn)

Codes

#include<bits/stdc++.h>

using namespace std;

const int mod = 1e9 + 7;
const int N = 5000 + 10;

int n, m, q, _pow2[N], flag;

string now[N], a[N], Que, L, R, tmp;

void Solve() {
    for(int i = 0; i < m; ++ i) now[i] = tmp;
    for(int i = n; i >= 1; -- i)
        for(int j = 0; j < m; ++ j)
            now[j][n - i] = a[i][j];
}

int Rank(string S) {
    int res = 0;
    for(int i = 0; i < n; ++ i)
        (res += _pow2[n - i - 1] * (S[i] - '0')) %= mod;
    return res;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("4424.in", "r", stdin);
    freopen("4424.out", "w", stdout);
#endif
	scanf("%d%d%d", &n, &m, &q);
	for(int i = 1; i <= n; ++ i) cin >> a[i];
	_pow2[0] = 1; tmp = a[1];
	for(int i = 1; i <= N - 5; ++ i) _pow2[i] = _pow2[i - 1] * 2 % mod;
	if(n > m) for(int i = 1; i <= n - m; ++ i) tmp += "1";
	if(n < m) for(int i = 1; i <= m - n; ++ i) tmp.pop_back();
	L = R = tmp; Solve();
	for(int cas = 1; cas <= q; ++ cas, flag = 0) {
		cin >> Que;
		for(int i = 0; i < n; ++ i)	L[i] = '0', R[i] = '1';
		for(int i = 0; i < m; ++ i) if(Que[i] == '1') flag = 1;
		for(int i = 0; i < m; ++ i) 
			if(Que[i] - '0') R = min(R, now[i]);
			else L = max(L, now[i]);
		if(L >= R) {puts("0"); continue;}
		printf("%d\n", (Rank(R) - Rank(L) + 1 - flag + mod) % mod);
	}
	return 0;
}


猜你喜欢

转载自blog.csdn.net/lunch__/article/details/82824338