C. 富豪凯匹配串
题目
给出 n 个长度为 m 的 01 串,有 q 次询问,每次给出一个长度 m 的字符串(只有 0,1,_),问之前 n 个串有多少可以匹配?( _ 可以匹配 0 或者 1)
n, m <1e3, q < 3e3
分析
考虑每次都把 n 遍历完(Onmq)肯定会超时。因此要优化每次的匹配过程。
这里用两个数组,ones[i][[j] 如果为 1,表示第 j 个串的 i 位置为 1。也就是说,如果想知道 i 位置有 0到n 的哪些串是 1,就看一下 ones[i] 这个数组即可。zeros 同理
做法:遍历 m 位置,ans[i] 存还有多少满足要求,每次迭代从 ans 种选出满足当前位置要求的,最后剩下来就是满足所有位置要求的。( 利用位运算 & 可以将每次 n 的遍历优化到 O1。)
代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define ll long long
#define fuck(x) cout<<x<<endl
const int N = 1e3 + 10;
const ll mod = 1e9 + 7;
int n, m, q;
char str[N][N], c[N];
bitset<N> ans, ones[N], zeros[N]; //ones[i] 表示 i 位置是 1 的下标
int main(){
scanf("%d%d", &n, &m);
for(int i = 0; i < n; i++){
scanf("%s", str[i]);
for(int j = 0; j < m; j++){
if(str[i][j] == '1')
ones[j][i] = 1;
else
zeros[j][i] = 1;
}
}
scanf("%d", &q);
while(q--){
scanf("%s", c);
ans.set(); // ans[i] 为 1 表示 i 号串满足要求
for(int i = 0; i < m; i++){
if(c[i] == '1')
ans &= ones[i];
if(c[i] == '0')
ans &= zeros[i];
}
printf("%d\n", ans.count()); // 数下有多少满足要求
}
return 0;
}