CF1270I Xor on Figures

把整个题写成形式幂级数,图形 \(F\) 表示为 \(\sum [F_{a,b}=1] x^ay^b\)。那么我们相当于要去确定一个操作矩阵 \(A\),使 \(A\times F\) 为目标矩阵 \(B\),即求 \(A=B\times F^{-1}\)

这里的卷积就是二维的循环卷积,即 \([x^ay^b](A\times F)=\oplus_{i+j=a,k+p=b}[x^iy^k]A\times [x^jy^p]F\)

考察 \(F^2\),对于 \([x^ay^b]F\) 转移到 \(x^cy^d\),它几乎都会被计算两次,除非 \(c=2a,d=2b\)。此时会转移恰好一次。

那么可以发现,把 \(F\) 平方只会使原来 \(=1\) 的下标翻倍。因为 \(F\) 有奇数个位置有值,所以 \(F^{2^k}\) 只会在 \(x^0y^0\) 处有值,即 \(F^{2^k}=1\)

因此有 \(F^{-1}=F^{2^k-1}\),我们只要算 \(B\times F^{2^k-1}\)。这个可以拆成 \(B\times F^{2^{k-1}}\times F^{2^{k-2}}\times\cdots\),而 \(F\)\(2^i\) 次幂只有 \(O(t)\) 个位置有值,暴力算即可。复杂度 \(O(tk2^k)\)

#include <bits/stdc++.h>
using namespace std;
using ull = unsigned long long;

const int kN = (1 << 9) + 5;
int n, N, m;

struct Matrix {
  ull a[kN][kN];
  Matrix() {
    memset(a, 0, sizeof(a));
  }
};
Matrix operator * (Matrix x, Matrix y) {
  static ull res[kN * 2][kN * 2];
  memset(res, 0, sizeof(res));
  for(int i = 0; i < N; i++) {
    for(int j = 0; j < N; j++) {
      if(!x.a[i][j]) continue;
      for(int k = 0; k < N; k++) {
        for(int p = 0; p < N; p++) {
          res[i + k][j + p] ^= x.a[i][j] * y.a[k][p];
        }
      }
    }
  }
  Matrix ans;
  for(int i = 0; i < N; i++) {
    for(int j = 0; j < N; j++) {
      ans.a[i][j] = res[i][j] ^ res[i + N][j] ^ res[i][j + N] ^ res[i + N][j + N];
    }
  }
  return ans;
}

int main() {
//  freopen("1.in", "r", stdin);
//  freopen("1.out", "w", stdout);
  ios::sync_with_stdio(0), cin.tie(0);
  Matrix a, f;
  cin >> n;
  N = (1 << n);
  for(int i = 0; i < N; i++) {
    for(int j = 0; j < N; j++) {
      cin >> a.a[i][j];
    }
  }
  cin >> m;
  for(int i = 1; i <= m; i++) {
    int x, y;
    cin >> x >> y;
    f.a[x - 1][y - 1] = 1;
  }
  for(int i = 0; i < n; i++) {
    a = f * a;
    f = f * f;
  }
  int ans = 0;
  for(int i = 0; i < N; i++) {
    for(int j = 0; j < N; j++) {
      ans += (a.a[i][j] != 0);
    }
  }
  cout << ans << "\n";
  return 0;
}
posted @ 2025-10-07 14:17  CJzdc  阅读(22)  评论(0)    收藏  举报