题目链接:hdu 4965,题目大意:给你一个 n*k 的矩阵 A 和一个 k*n 的矩阵 B,定义矩阵 C= A*B,然后矩阵 M= C^(n*n),矩阵中一切元素皆 mod 6,最后求出 M 中所有元素的和。题意很明确了,便赶紧敲了个矩阵快速幂的模板(因为编程的基本功不够还是调试了很久),然后提交后TLE了,改了下细节,加了各种特技,比如输入优化什么的,还是TLE,没办法,只好搜题解,看了别人的题解后才知道原来 A*B 已经是 n*n 的矩阵了,所以(A*B)n*n 的快速幂里的每个乘法都是 n3 级别的了,n 的上限为1000,这样子超时也不奇怪了,怎么办呢,原来是要转化一下:(A*B)n*n= A*(B*A)n*n-1*A,这样子的话,B*A 是 k*k 的矩阵,乘法是 k3 级别的,k<=6,就不会超时了,这个转化果然好厉害!
如果结构体内直接开个数组的话会超内存,要用指向一维数组的指针来 new 才行,不过还是很容易出错:
1 #include<cstdio> 2 #include<cstring> 3 #include<cctype> 4 #include<algorithm> 5 using namespace std; 6 #define For(i,s,t) for(int i=s; i<=t; ++i) 7 const int mod= 6; 8 const int maxn= 1002; 9 10 struct matrix{ 11 int n,m, (*a)[maxn]= NULL; 12 matrix(int n=1, int m=1):n(n),m(m){ 13 a= new int[n+2][maxn]; 14 For(i,1,n) For(j,1,m) 15 a[i][j]= 0; 16 } 17 void identity(){ 18 For(i,1,n) a[i][i]= 1; 19 } 20 matrix operator *(const matrix &m2) const { 21 matrix mul(n,m2.m); 22 For(i,1,n) For(j,1,m2.m) For(k,1,m) 23 mul.a[i][j]= (mul.a[i][j]+a[i][k]*m2.a[k][j]%mod)%mod; 24 return mul; 25 } 26 int sum(){ 27 int ans= 0; 28 For(i,1,n) For(j,1,m) 29 ans+= a[i][j]; 30 return ans; 31 } 32 void clear() { delete[] a; } 33 }; 34 35 matrix quick_mod(matrix m2, int p){ 36 matrix ans(m2.n,m2.m); 37 ans.identity(); 38 while(p){ 39 if(p&1) ans= ans*m2; 40 m2= m2*m2; 41 p>>=1; 42 } 43 return ans; 44 } 45 46 void read(int &x){ 47 x= 0; 48 char ch= getchar(); 49 while(!isdigit(ch)) ch= getchar(); 50 while(isdigit(ch)){ 51 x= x*10+(ch-'0'+0); 52 ch= getchar(); 53 } 54 } 55 56 int main(){ 57 int n,k; 58 read(n); read(k); 59 while(2){ 60 if(!n || !k) break; 61 matrix A(n,k), B(k,n), tmp(k,k), C(n,n); 62 For(i,1,n) For(j,1,k) read(A.a[i][j]); 63 For(i,1,k) For(j,1,n) read(B.a[i][j]); 64 tmp= B*A; 65 tmp= quick_mod(tmp,n*n-1); 66 C= A*tmp*B; 67 printf("%d\n",C.sum()); 68 read(n); read(k); 69 A.clear(); 70 B.clear(); 71 tmp.clear(); 72 C.clear(); 73 } 74 return 0; 75 }
用指向一维数组的指针貌似挺耗费内存的,于是改用了二级指针来试下,果然内存和效率都明显有了很大的提高(但好像还是比不上 vector 耶~):
1 #include<cstdio> 2 #include<cstring> 3 #include<cctype> 4 #include<algorithm> 5 using namespace std; 6 #define For(i,s,t) for(int i=s; i<=t; ++i) 7 const int mod= 6; 8 const int maxn= 1002; 9 10 struct matrix{ 11 int n,m, **a= NULL; 12 matrix(int n=1, int m=1):n(n),m(m){ 13 a= new int *[n+2]; 14 For(i,1,n) a[i]= new int[m+2]; 15 For(i,1,n) For(j,1,m) 16 a[i][j]= 0; 17 } 18 void identity(){ 19 For(i,1,n) a[i][i]= 1; 20 } 21 matrix operator *(const matrix &m2) const { 22 matrix mul(n,m2.m); 23 For(i,1,n) For(j,1,m2.m) For(k,1,m) 24 mul.a[i][j]= (mul.a[i][j]+a[i][k]*m2.a[k][j]%mod)%mod; 25 return mul; 26 } 27 int sum(){ 28 int ans= 0; 29 For(i,1,n) For(j,1,m) 30 ans+= a[i][j]; 31 return ans; 32 } 33 void clear(){ 34 For(i,1,n) delete a[i]; 35 delete a; 36 a = NULL; 37 } 38 }; 39 40 matrix quick_mod(matrix m2, int p){ 41 matrix ans(m2.n,m2.m); 42 ans.identity(); 43 while(p){ 44 if(p&1) ans= ans*m2; 45 m2= m2*m2; 46 p>>=1; 47 } 48 return ans; 49 } 50 51 void read(int &x){ 52 x= 0; 53 char ch= getchar(); 54 while(!isdigit(ch)) ch= getchar(); 55 while(isdigit(ch)){ 56 x= x*10+(ch-'0'+0); 57 ch= getchar(); 58 } 59 } 60 61 int main(){ 62 int n,k; 63 read(n); read(k); 64 while(2){ 65 if(!n || !k) break; 66 matrix A(n,k), B(k,n), tmp(k,k), C(n,n); 67 For(i,1,n) For(j,1,k) read(A.a[i][j]); 68 For(i,1,k) For(j,1,n) read(B.a[i][j]); 69 tmp= B*A; 70 tmp= quick_mod(tmp,n*n-1); 71 C= A*tmp*B; 72 printf("%d\n",C.sum()); 73 read(n); read(k); 74 A.clear(); 75 B.clear(); 76 tmp.clear(); 77 C.clear(); 78 } 79 return 0; 80 }
后来无意中看到别人的代码用 vector 来代替动态数组就行,不用自己手动 new 和 delete 了,确实方便了好多:
1 #include<cstdio> 2 #include<cstring> 3 #include<cctype> 4 #include<vector> 5 #include<algorithm> 6 using namespace std; 7 #define For(i,s,t) for(int i=s; i<=t; ++i) 8 const int mod= 6; 9 const int maxn= 1002; 10 11 struct matrix{ 12 int n,m; 13 vector<vector<int> > a; 14 matrix(int n=1, int m=1):n(n),m(m){ 15 a.resize(n+1); 16 For(i,1,n) a[i].resize(m+1,0); 17 } 18 void identity(){ 19 For(i,1,n) a[i][i]= 1; 20 } 21 matrix operator *(const matrix &m2) const { 22 matrix mul(n,m2.m); 23 For(i,1,n) For(j,1,m2.m) For(k,1,m) 24 mul.a[i][j]= (mul.a[i][j]+a[i][k]*m2.a[k][j]%mod)%mod; 25 return mul; 26 } 27 int sum(){ 28 int ans= 0; 29 For(i,1,n) For(j,1,m) 30 ans+= a[i][j]; 31 return ans; 32 } 33 ~matrix() { 34 For(i,1,n) a[i].clear(); 35 a.clear(); 36 } 37 }; 38 39 matrix quick_mod(matrix m2, int p){ 40 matrix ans(m2.n,m2.m); 41 ans.identity(); 42 while(p){ 43 if(p&1) ans= ans*m2; 44 m2= m2*m2; 45 p>>=1; 46 } 47 return ans; 48 } 49 50 void read(int &x){ 51 x= 0; 52 char ch= getchar(); 53 while(!isdigit(ch)) ch= getchar(); 54 while(isdigit(ch)){ 55 x= x*10+(ch-'0'+0); 56 ch= getchar(); 57 } 58 } 59 60 int main(){ 61 int n,k; 62 read(n); read(k); 63 while(2){ 64 if(!n || !k) break; 65 matrix A(n,k), B(k,n), tmp(k,k), C(n,n); 66 For(i,1,n) For(j,1,k) read(A.a[i][j]); 67 For(i,1,k) For(j,1,n) read(B.a[i][j]); 68 tmp= B*A; 69 tmp= quick_mod(tmp,n*n-1); 70 C= A*tmp*B; 71 printf("%d\n",C.sum()); 72 read(n); read(k); 73 } 74 return 0; 75 }
看来自己曾经引以为傲的矩阵快速幂还差得很远啊~~总之得加把劲了!