版权声明:_ https://blog.csdn.net/lunch__/article/details/82824338
题意
- 给你 个 串, 次询问,每次询问一个 串,问在每个 串前添加&或|,有多少种方案使得最后的结果为询问的串,对 取模
这个题看了好久题解才会做… 做题要心静啊
首先考虑按位处理 对于其中的每一位我们提出来看
首先我们观察一下位运算的一些性质
这说明如果 的话这位的值就和前面的没关系 同理
这说明如果 的话这位的值就和当前位没关系 同理
那么我们把运算符变成 序列,
那么如果某一位上的值是 的话
那么它最后一个 一定在最后一个 前面
是 , 是 转化一下就是
运算符序列的字典序小于当前序列
同理那一位是 就是字典序大于等于当前序列
那么这个题目就转化成了一个求字符串字典序的题
直接用 就好了 有些细节要注意
注意下询问全 序列,因为我们的区间 是前闭后开
但是对于全 序列来说全部用 操作也是合法的
然后就做完了 复杂度
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;
}