2020 CCPC Wannafly Winter Camp Day5 J Xor on Figures(矩阵转01串,统计01串异或种类)
题:https://ac.nowcoder.com/acm/contest/4120/J
题意:一个初始全0矩阵M,给定一个相同大小的01矩阵F,允许操作为选择M中某一个位置放入F,然后M=M xor F 若超出范围则按题目那样转移;
你可以用任意次操作,问所有操作所有能生成的最后的M的种类;
分析:其实这题不难,关键是能保持清晰看完的心态;
给定的矩阵大小很小,可以直接枚举每个位置放入F,再转化为01串,看最后的M能由哪些异或出来;
其实就是“给定一些数,问最后能异或出来多少个数”,这就是线性基的绝活,长度太长,用bitset来处理
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define lson root<<1,l,midd #define rson root<<1|1,midd+1,r const int mod=1e9+7; const int N=1100; char s[N][N]; bitset<N>p[N],a[N]; int T,k; struct LB{ void Insert(bitset<N> x){ for(int i=T*T;i>=1;i--){ if(x[i]){ if(p[i].count()>=1) x^=p[i]; else{ for(int j=0;j<=i-1;j++) if(x[j]) x^=p[j]; for(int j=i+1;j<=T*T;j++) if(p[j][i]) p[j]^=x; p[i]=x; return ; } } } } ll getvec(){ ll res=0; for(int i=1;i<=T*T;i++) if(p[i].count()>=1) res++; return res; } }lb; ll ksm(ll x,ll y){ ll t=1ll; while(y){ if(y&1) t=t*x%mod; y>>=1; x=x*x%mod; } return t; } int main(){ scanf("%d",&k); T=1<<k; for(int i=1;i<=T;i++) scanf("%s",s[i]+1); auto getid = [&](int x,int y){ return (x-1)*T+y; }; for(int x=1;x<=T;x++)///枚举(x,y)作为F的左上角起点 for(int y=1;y<=T;y++){ int u=getid(x,y); for(int i=1;i<=T;i++)///枚举(i,j)看F上这个位置是否为1,构建01串 for(int j=1;j<=T;j++){ if(s[i][j]=='1'){ a[u][getid( (x+i-1)%T+1 , (y+j-1)%T+1 )]=1; ///printf("%d %d\n",u,getid( (x+i-1)%T+1 , (y+j-1)%T+1 )); } } } for(int i=1;i<=T*T;i++){ lb.Insert(a[i]); } ///异或和的种类可以通过线性基来求 printf("%lld\n",ksm(2ll,lb.getvec())); return 0; }