CF1270I Xor on Figures
题目传送门
分析:
我们考虑定义一个矩阵乘法运算\(A\times B=C\),注意以下所有关于下标的运算都是对\(n=2^k\)取模意义下的
\(C[x][y]=\oplus_{i=0}^{n-1}\oplus_{j=0}^{n-1}(A[i][j]*B[x-i][y-j])\)
这是\(O(n^4)\)的,其中\(\oplus\)是求异或和
设输入的矩阵为\(A\)
创建一个矩阵\(F\)使得\(F[x_i][y_i]\)为1,其余为0
我们想找到一个矩阵\(C\),使得\(C\times F=A\)
答案其实就是矩阵\(C\)上值不为0的位置个数
其实这个乘法相当于在实现整个过程,我们来想办法解决这个逆过程
显然\(C=A\times F^{-1}\)
首先我们想知道\(F\)是否有逆矩阵
即\(F\times F^{-1}=I\)
观察上面的定义,发现\(I\)除了\(I[0][0]\)为1,其余位置都是0
找一找\(F\)的规律吧
首先对于\(F^2\),只有\([2x_i][2y_i]\)为1,其余位置如\([x_i+x_j][y_i+y_j]\)会被\(([x_i][y_i]*[x_j][y_j])\oplus([x_j][y_j]*[x_i][y_i])\)直接抵消
同理,对于\(F^{2^k}\),只有\([2^{k}x_i][2^{k}y_i]\)的值为1,模\(n\)意义下只有\([0][0]\)为1(\(t\)为奇数,最后异或起来一定为\(1\))
惊奇地发现\(F^{2^k}=I\)
那么\(F^{2^{k}-1}=F^{-1}\)
所以\(C=A\times F^{2^{k}-1}\)
注意到\(F\)上最多只有\(t\)个值,所以可以把\(O(n^4)\)的运算优化为\(O(tn^2)\)
模拟这个过程就好了
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<queue>
#include<algorithm>
#define maxn 1005
#define INF 0x3f3f3f3f
#define MOD 998244353
using namespace std;
inline long long getint()
{
long long num=0,flag=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
return num*flag;
}
int n,k,t,ans;
long long F[2][maxn][maxn];
int now=1,pre;
int X[maxn],Y[maxn];
inline void solve()
{
memset(F[now],0,sizeof F[now]);
for(int i=0;i<n;i++)for(int j=0;j<n;j++)
for(int k=1;k<=t;k++)F[now][(i+X[k])&(n-1)][(j+Y[k])&(n-1)]^=F[pre][i][j];
for(int i=1;i<=t;i++)X[i]=(X[i]<<1)&(n-1),Y[i]=(Y[i]<<1)&(n-1);
}
int main()
{
k=getint();n=1<<k;
for(int i=0;i<n;i++)for(int j=0;j<n;j++)F[pre][i][j]=getint();
t=getint();
for(int i=1;i<=t;i++)X[i]=getint()-1,Y[i]=getint()-1;
while(k--)solve(),swap(now,pre);
for(int i=0;i<n;i++)for(int j=0;j<n;j++)if(F[pre][i][j])ans++;
printf("%d\n",ans);
}