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;
}