这道题有点厉害..
考虑 \(or\) \(and\) 运算的性质
如果在某一个位置\(and\)上\(0\) 或者 \(or\)上\(1\)
是不是前面的操作都白费了
于是按位考虑 压缩一下状态 以最右边的数作为最高位
设对于位\(i\)的状态是\(b_i\)
操作的序列同样压缩成\(op\)
\(or\) 是 \(0\) \(and\) 是 \(1\) (其实只需要建立一个\(and, or\) 和\(bit0, bit1\)的偏序关系就好了)
如果对于\(ans_i = 1\) 那么有\(b_i > op\)
同理对于\(ans_i = 0\) 那么有\(b_i \le op\)
统计答案的时候就是解若干个关于op的方程组
合并成\(l \le op < r\)的形式 那么\(result = r - l\)
解方程组的话可以先对\(\{b\}\)排序考虑第一次出现\(0,1\)位置
复杂度\(O((q + n) \times m)\)
#include <bits/stdc++.h>
#define int long long
#define fo(i, n) for(int i = 1; i <= (n); i ++)
#define out(x) cerr << #x << " = " << x << "\n"
#define type(x) __typeof((x).begin())
#define foreach(it, x) for(type(x) it = (x).begin(); it != (x).end(); ++ it)
using namespace std;
// by piano
template<typename tp> inline void read(tp &x) {
x = 0;char c = getchar(); bool f = 0;
for(; c < '0' || c > '9'; f |= (c == '-'), c = getchar());
for(; c >= '0' && c <= '9'; x = (x << 3) + (x << 1) + c - '0', c = getchar());
if(f) x = -x;
}
template<typename tp> inline void arr(tp *a, int n) {
for(int i = 1; i <= n; i ++)
cout << a[i] << " ";
puts("");
}
const int M = 5555;
const int mo = 1e9 + 7;
template<typename tp> inline int sub(tp a, tp b) {
int ans = a - b; for(; ans < 0; ans += mo); return ans;
}
struct Node {
vector<int> vec;
int ha, id;
}a[M];
int n, m, q;
int r[M], rnk[M], pw[M];
char str[M];
inline bool cmp(const Node &a, const Node &b) {
for(int k = n - 1; k >= 0; k --)
if(a.vec[k] != b.vec[k])
return a.vec[k] < b.vec[k];
return a.id < b.id;
}
main(void) {
read(n); read(m); read(q);
pw[0] = 1;
for(int i = 1; i <= n; i ++)
pw[i] = pw[i - 1] * 2 % mo;
for(int i = 1; i <= n; i ++) {
scanf("%s", str + 1);
for(int k = 1; k <= m; k ++)
a[k].vec.push_back(str[k] - '0');
}
for(int i = 1; i <= m; i ++) {
int ha = 0;
for(int k = n - 1; k >= 0; k --)
ha = (ha * 2 + a[i].vec[k]) % mo;
a[i].ha = ha; a[i].id = i;
}
sort(a + 1, a + m + 1, cmp); reverse(a + 1, a + m + 1);
for(int k = 1; k <= m; k ++) rnk[a[k].id] = k;
for(int i = 1; i <= q; i ++) {
scanf("%s", str + 1);
for(int k = 1; k <= m; k ++)
r[rnk[k]] = str[k] - '0';
int last1 = -1, first0 = m + 1;
for(int k = 1; k <= m; k ++)
if(r[k] == 0) {
first0 = k;
break;
}
for(int k = m; k >= 1; k --)
if(r[k] == 1) {
last1 = k;
break;
}
if(first0 < last1) puts("0");
else {
if(last1 == -1) cout << sub(pw[n], a[first0].ha) << "\n";
else cout << sub(a[last1].ha, a[last1 + 1].ha) << "\n";
}
}
}
原文地址:https://www.cnblogs.com/foreverpiano/p/8987475.html
时间: 2024-10-11 18:42:51