1. 程式人生 > 實用技巧 >2020 CCPC Wannafly Winter Camp Day5 J Xor on Figures(矩陣轉01串,統計01串異或種類)

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來處理

#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; }
View Code