专栏文章

CF1270I Xor on Figures 题解

CF1270I题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minnazzq
此快照首次捕获于
2025/12/02 05:12
3 个月前
此快照最后确认于
2025/12/02 05:12
3 个月前
查看原文
联考搬的神仙题。
有一种 naive 的想法是把这个操作刻画成一个矩阵,然后用 bitset 跑异或高斯消元,答案是增广列中非零系数的个数。在联考中过了 k7k\le 7
接下来就是人类智慧了。
我们定义矩阵乘法 A×B=CA\times B=C。具体的,Ci,j=x,yax,ybix,jyC_{i,j}=\oplus_{x,y}a_{x,y}b_{i-x,j-y},注意这里的 ixi-xjyj-y 均是在模意义下的。
据我测试得出,这个运算不满足结合律,这个在接下来会避免踩坑。
由于异或操作的自反性,我们将初始矩阵变成全零矩阵,就是全零矩阵变成初始矩阵。
AA 为初始矩阵,BB 为“操作矩阵”(具体地,在第 ii 次操作中,把 Bxi,yiB_{x_i,y_i} 设成 11 即可)。
那么我们要找到一个矩阵 CC,满足:A=B×CA=B\times C。答案就是矩阵 CC 中非零系数的个数。
不难得出 C=A×B1C=A\times B^{-1}。我们只需要找到 BB 的逆矩阵即可。
令单位矩阵为 II,那么有 I0,0=1I_{0,0}=1Ii,j=0I_{i,j}=0(显然 i0i\ne0j0j\ne 0)。
我们发现对于矩阵 TTT2T^2 就是将 TT(x,y)(x,y) 的点的值转移到 (2x,2y)(2x,2y)(因为其它点位都会被异或抵消,而 (2x,2y)(2x,2y) 不变)。
也就是说 T2kT^{2^k} 就是一个单位矩阵!
那么我们要找的逆矩阵其实就是 T2k1T^{2^k-1}
然后我们就只需要求 C=A×B2k1C=A\times B^{2^k-1} 即可。
好,还记得上面说的“跳坑”吗?
因为传统的矩阵快速幂是需要满足结合律的,这样才能先算 B2k1B^{2^k-1},再算 A×B2k1A\times B^{2^k-1}
但这个很好解决,我们将传统的矩阵快速幂中,初始矩阵(即单位矩阵)改成 AA 即可。
本题轻微卡常,大概可以优化两个点:
  • 矩乘时,在 ax,y=0a_{x,y}=0 的时候不做下面的枚举。
  • 把取模改成位运算。
代码和讲解稍有出入:
CPP
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1000010;
const int mod=1e9+7;
const int INF=0x3f3f3f3f3f3f3f3f;
const int M=1<<9;//size of matrix
int mask;
struct matrix{
	int n,a[M][M];
	matrix(int _n){
		n=_n;
		memset(a,0,sizeof(a));
	}
	friend matrix operator * (matrix a,matrix b){
		int n=a.n;
		matrix c(n);
        for(int i=0;i<n;++i)
            for(int j=0;j<n;++j)
                if(a.a[i][j])
                    for(int k=0;k<n;++k)
                        for(int l=0;l<n;++l)
                            c.a[(i+k)&mask][(j+l)&mask]^=a.a[i][j]*b.a[k][l];
		return c;
	}
};
int k,t;
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    // freopen("mc.in","r",stdin);
    // freopen("mc.out","w",stdout);
	cin>>k;
    int prek=k;
	k=(1<<k);
    mask=k-1;
	matrix A(k),T(k);
	for(int i=0;i<k;i++){
		for(int j=0;j<k;j++){
			cin>>A.a[i][j];
		}
	}
    cin>>t;
	for(int i=1;i<=t;i++){
		int x,y;
		cin>>x>>y;
		x--;y--;
		T.a[x][y]=1;
	}
    matrix ans=A;//这个运算不满足结合律,所以只能这么写
    for(int i=0;i<prek;i++){
        ans=T*ans;
        T=T*T;
    }
	int cnt=0;
	for(int i=0;i<k;i++)for(int j=0;j<k;j++)cnt+=(ans.a[i][j]!=0);
	cout<<cnt<<"\n";
	return 0;
}
/*

*/

评论

0 条评论,欢迎与作者交流。

正在加载评论...