牛客國慶集訓派對Day3
阿新 • • 發佈:2018-12-13
題意:矩陣A,每個數用十六進位制表示,矩陣B,一列用一個二進位制數表示,一個數為一個0或者1。求矩陣C=A*B中每個元素的異或和。
思路:可以看的出來B的每一列的二進位制數就相當於A中某一行的元素中某一列元素是否要加上。比如01011,那麼A中對應第一列和第三列的元素就不用加,那麼我們可以通過預處理所有狀態求出每個狀態當前那一行的元素和。由於要節省時間,那麼我們可以每8列合併成一個整體計算狀態,這樣一塊的狀態就只有256種。然後按正常矩陣乘就行了。
#include<cstdio> #include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<string> #include<map> #include<vector> #include<queue> using namespace std; #define PI acos(-1) #define INF 0x3f3f3f3f #define NUM 50100 #define debug false #define ll long long #define lowbit(x) ((-x)&x) #define ffor(i,d,u) for(int i=d;i<=u;++i) #define _ffor(i,u,d) for(int i=u;i>=d;--i) #define mst(array,Num) memset(array,Num,sizeof(array)) const int P = 1e9+7; int n,p,m; int a[4100][66]={},b[4100][10]={},na[4100][256][10]={},pos[256]; template <typename T> void read(T& x) { x=0; char c;T t=1; while(((c=getchar())<'0'||c>'9')&&c!='-'); if(c=='-'){t=-1;c=getchar();} do(x*=10)+=(c-'0');while((c=getchar())>='0'&&c<='9'); x*=t; } template <typename T> void write(T x) { int len=0;char c[21]; if(x<0)putchar('-'),x*=(-1); do{++len;c[len]=(x%10)+'0';}while(x/=10); _ffor(i,len,1)putchar(c[i]); } void AC() { char c[23]; pos[0]=0; ffor(i,1,255)pos[i]=lowbit(i); ffor(i,1,255) { int j=0; while((pos[i]&1)!=1) ++j,pos[i]>>=1; pos[i]=j; }//求狀態i最右邊1的位置 read(n),read(p),read(m); ffor(i,1,n)ffor(j,1,p)scanf("%x",&a[i][j]); ffor(i,1,m) { getchar(); int j=1,k=0; while(j<=p) { b[i][(j-1)>>3]+=((getchar()-'0')<<k); (++k)%=8; ++j; } } int p1=((p-1)>>3)+1; int sum,ans=0; ffor(i,1,n) ffor(j,0,p1-1) ffor(k,1,255) { if((j<<3)+pos[k]+1>p)continue ; na[i][k][j]=na[i][k-(1<<pos[k])][j]+a[i][(j<<3)+pos[k]+1];//求第i行第j+1個分塊在k狀態下的和 } ffor(i,1,n) ffor(j,1,m) { sum=0; ffor(k,0,p1-1)sum+=na[i][b[j][k]][k]; ans^=sum; } write(ans),putchar('\n'); } int main() { AC(); return 0; }