CF1270I Xor on Figures

题目传送门

分析:
我们考虑定义一个矩阵乘法运算(A imes 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 imes F=A)
答案其实就是矩阵(C)上值不为0的位置个数
其实这个乘法相当于在实现整个过程,我们来想办法解决这个逆过程
显然(C=A imes F^{-1})
首先我们想知道(F)是否有逆矩阵
(F imes 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 imes 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
",ans);
}

原文地址:https://www.cnblogs.com/Darknesses/p/12976392.html