uoj425
题意
给 \(q\) 个长度为 \(n\) 的带 \(?\) 的 \(01\) 串 \(T\)。
求有多少长度为 \(n\) 的 \(01\) 串存在 \(T\) 中至少一个串能匹配。\(?\ =\ 0\ or\ 1\)。
做法1
meet-in-middle 考虑如何合并
暴力做法先搜一半,对 \(T\) 中每个串记录一个 \(2^{\frac{n}{2}}\) 的 bitset 看哪些串匹配。搜另一半的时候将 \(T\) 中匹配的串的 bitset 或起来求个 count。
可以将 \(T\) 分成 \(B\) 块,搜好一半时对块内的 \(2^B\) 个子集算下至少匹配这些串的 bitset。搜另一半时只用或 \(\frac{q}{B}\) 个 bitset。
时间复杂度 \(O(\frac{2^nq}{wB})\)。
代码
#include <bits/stdc++.h>
#ifdef __WIN32
#define LLFORMAT "I64"
#else
#define LLFORMAT "ll"
#endif
using namespace std;
const int B = 10, S = 1 << 15, N = 100;
bitset<S> pool[N / B][1 << B];
int main() {
ios::sync_with_stdio(false);
vector<int> pw2(B);
for (int i = 0; i < B; ++i) pw2[i] = 1 << i;
int n, q;
cin >> n >> q;
vector<string> s(q);
vector<int> bel(q), id(q);
for (int i = 0; i < q; ++i) cin >> s[i], bel[i] = i / B, id[i] = ((i == 0 || bel[i] != bel[i - 1]) ? 0 : id[i - 1] + 1);
string str(n, '?');
int m = n >> 1;
function<void(int)> dfs1 = [&](int i) {
static int x = 0;
if(i == n) {
for (int j = 0; j < q; ++j) {
bool flag = true;
for (int i = m; i < n; ++i) if((s[j][i] != '?') && (s[j][i] != str[i])) { flag = false; break; }
if(flag) pool[bel[j]][pw2[id[j]]].set(x);
}
++x;
return;
}
str[i] = '0';
dfs1(i + 1);
str[i] = '1';
dfs1(i + 1);
return;
};
dfs1(m);
for (int i = 0; i <= bel.back(); ++i) {
static int S = 1 << B;
for (int s = 1, t; t = s & (-s), s < S; ++s) pool[i][s] = pool[i][t] | pool[i][s ^ t];
}
int ans = 0;
function<void(int)> dfs2 = [&](int i) {
static bitset<S> all;
if(i == m) {
all.reset();
for (int S = 0, j = 0; j < q; ++j) {
bool flag = true;
for (int i = 0; i < m; ++i) if((s[j][i] != '?') && (s[j][i] != str[i])) { flag = false; break; }
if(flag) S |= pw2[id[j]];
if(j == q - 1 || bel[j + 1] != bel[j]) all |= pool[bel[j]][S], S = 0;
}
ans += all.count();
return;
}
str[i] = '0';
dfs2(i + 1);
str[i] = '1';
dfs2(i + 1);
return;
};
dfs2(0);
cout << ans << endl;
return 0;
}