毒蛇脱走
毒蛇脱走
首先这题肯定要用到 FWT 之类的 \(O(L2^L)\) 的东西。
观察一下,朴素的想法是通过某种方式求出所有答案,但是发现可能的询问是 \(O(3^L)\) 级别的,所以寄。
不妨考虑我们可以干什么,发现我们会做询问只有两种字符的所有情况。具体的如果是 0
和 1
那么直接拿出来,否则相当于一个高维前缀和了,可以预处理后直接做。
那么考虑转化到只有两种字符,这个东西严格比拼图与排列简单,直接容斥即可。
const int N = 1 << 20 | 5;
int L, q;
string S;
string T;
struct Query {
int id, x;
};
int c[N], f[N], g[N]; // 0&1; 0&?; 1&?
void work(int *f, int n) {
for(int i = 1; i <= n; i <<= 1)
for(int j = 0; j <= n; ++j)
if(j & i) f[j] += f[j ^ i];
}
vector<int> bit;
int o, k;
int ans;
char ch;
const int sgn[] = {1, -1};
#define pc(x) __builtin_popcount(x)
void dfs(int j, int s) {
if(j == k) {
if(ch == '0') ans += g[s | o] * sgn[(k - pc(s)) & 1];
else if(ch == '1') ans += f[s | o] * sgn[(k - pc(s)) & 1];
else ans += c[s | o];
return ;
}
dfs(j + 1, s | 1 << bit[j]);
dfs(j + 1, s);
}
#undef pc
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> L >> q;
cin >> S;
int u = (1 << L) - 1;
for(int i = 0; i <= u; ++i)
c[i] = S[i] - '0', f[i] = S[i] - '0', g[i] = S[u ^ i] - '0';
work(f, u), work(g, u);
for(int i = 1; i <= q; ++i) {
cin >> T;
int a = 0, b = 0, c = 0;
for(int j = 0; j < L; ++j) {
if(T[j] == '0') ++a;
else if(T[j] == '1') ++b;
else ++c;
}
if(a < 7) {
ch = '0', k = a;
} else if(b < 7) {
ch = '1', k = b;
} else {
ch = '?', k = c;
}
o = 0;
bit.clear();
for(int j = 0; j < L; ++j) {
if(T[j] == ch) bit.eb(L - j - 1);
else {
if(ch == '?') {
if(T[j] == '1') o |= 1 << (L - j - 1);
} else {
if(T[j] == '?') o |= 1 << (L - j - 1);
}
}
}
ans = 0;
dfs(0, 0);
cout << ans << '\n';
}
}