毒蛇脱走

毒蛇脱走

首先这题肯定要用到 FWT 之类的 \(O(L2^L)\) 的东西。

观察一下,朴素的想法是通过某种方式求出所有答案,但是发现可能的询问是 \(O(3^L)\) 级别的,所以寄。

不妨考虑我们可以干什么,发现我们会做询问只有两种字符的所有情况。具体的如果是 01 那么直接拿出来,否则相当于一个高维前缀和了,可以预处理后直接做。

那么考虑转化到只有两种字符,这个东西严格比拼图与排列简单,直接容斥即可。

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';
  }
}
posted @ 2024-01-03 09:01  DCH233  阅读(5)  评论(0编辑  收藏  举报