ACM-ICPC 2018 徐州賽區網路預賽 K. Morgana Net (矩陣快速冪)
阿新 • • 發佈:2018-11-19
給你一個n*n的矩陣A,和一個m*m的矩陣B(m%2==1)
B是卷積核,讓你用B對A做t次卷積運算,並且對於A中的每一個元素計算出來的值要模2,所以A最後會是一個01矩陣。
問你經過t此後,A中有多少個元素=1
1<=t<=1e9,1<=n<=8,1<=m<=n
解析:
這道題按理來說就是一道很普通的矩陣快速冪的題目,但是比賽裡只有95個做出來...而且計蒜客還把這道題難度標成3星...
這個導致我以為是什麼數學公式,就直接搜了卷積轉換成矩陣乘法的公式,嗯...確實3星..要用到Toeplitz矩陣...
然後搜了題解...矩陣快速冪,構造矩陣...?????
這道題之所以能用矩陣快速冪是因為這個n實在太小了..你把每一個元素拿出來也才64個元素...
那麼做法就是把A矩陣變成一個1*(n*n)的一維向量,然後構造一個(n*n)*(n*n)的輔助矩陣
我們觀察到對於A中的每一個元素,每一次卷積運算,所要求乘積的值的位置是固定的,那麼我們就提前預處理出
對於A中的每一個元素求出參與該元素的卷積運算的對應元素的位置。
這樣複雜度是O(T*n^6*logt),因為這裡有多組資料T=100,所以可能會有卡常,需要用biset優化一下
最終的複雜度就是O(T*n^4*logt)
#include <cstdio> #include <algorithm> #include <cstring> #include <bitset> using namespace std; typedef long long ll; const int MOD = 2; const int MAXN = 40000; typedef struct { bitset<80> m[80]; int sizx,sizy; }Matrix; int n,m; Matrix cb; inline Matrix Mul(Matrix a, Matrix b) { Matrix c; c.sizx=a.sizx; c.sizy=b.sizy; cb.sizy=b.sizx; cb.sizx=b.sizy; for(int i=0;i<b.sizy;i++) { cb.m[i].reset(); for(int j=0;j<b.sizx;j++) { cb.m[i][j]=b.m[j][i]; } } for (int i = 0; i < a.sizx; i++) { c.m[i].reset(); for (int j = 0; j < b.sizy; j++) { bitset<80> tmp=(a.m[i]&cb.m[j]); c.m[i][j]=tmp.count()&1; } } return c; } inline Matrix fastm(Matrix a, ll num) { Matrix res; for(int i=0;i<a.sizx;i++) res.m[i].reset(); res.sizx=a.sizx; res.sizy=a.sizy; for(int i=0;i<a.sizx;i++) res.m[i][i]=1; while (num) { if (num & 1) res = Mul(res, a); num >>= 1; a = Mul(a, a); } return res; } Matrix a,b,c; int main() { int cas; scanf("%d",&cas); while(cas--) { int t; scanf("%d%d%d",&n,&m,&t); a.sizx=1;a.sizy=n*n; a.m[0].reset(); for(int i=0;i<n*n;i++) { int tmp; scanf("%d",&tmp); a.m[0][i]=tmp&1; } for(int i=0;i<m;i++) { for(int j=0;j<m;j++) { int tmp; scanf("%d",&tmp); b.m[i][j]=tmp&1; } } c.sizx=c.sizy=n*n; int num=0; int in=0; m=m>>1; for(int i=0;i<n*n;i++) c.m[i].reset(); for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { for(int p=i-m;p<=i+m;p++) { for(int q=j-m;q<=j+m;q++) { in=p*n+q; if(p>=0&&p<n&&q>=0&&q<n) { c.m[in][num]=(b.m[p-i+m][q-j+m]); } } } num++; } } c=fastm(c,t); a=Mul(a,c); printf("%d\n",a.m[0].count()); } }