传送门:点击打开链接
题意:在M*N的棋盘里放象棋中的马,使得马之间互不攻击,问种类数, M<=4,N<=1e9
思路:很明显是快速矩阵幂,问题是如何构造矩阵。
我的想法是保存两行的状态,状态的个数是 2^(2*m),然后构造出来的矩阵大小是2^(2*m)*2^(2*m)
最后的总复杂度是 O(2^(6*m)*logn),这个复杂度也是巨大了,吓得我差点不敢写,,不过好在秒数很大。。
关于矩阵的构造,就是一个DFS就搞定了,用DFS去按照列的个数从小到大枚举,然后再用二进制去枚举哪些位置放哪些位置不放。
然后再考虑放的时候要注意哪些位置不能已经放了,然后跑个DFS矩阵就出来了,这种方法是快速矩阵幂中常用的一种求矩阵的方法。
比较胆小,,刚开始用vec封装的矩阵,本地跑起来超级慢,当然跟笔记本配置比较渣有点关系。
然后就把动态申请第一次改写成了静态的矩阵,感觉略有奇葩,不过优化效果还是不错的。
#include<map> #include<set> #include<cmath> #include<ctime> #include<stack> #include<queue> #include<cstdio> #include<cctype> #include<string> #include<vector> #include<cstring> #include<iomanip> #include<iostream> #include<algorithm> #include<functional> #define fuck(x) cout<<"["<<x<<"]" #define FIN freopen("input.txt","r",stdin) #define FOUT freopen("output.txt","w+",stdout) using namespace std; typedef long long LL; typedef pair<int, int>PII; const int MX = 260; const int mod = 1e9 + 9; const int INF = 0x3f3f3f3f; int M[80], N[80], rear; int W[80][MX][MX]; int New(int m, int n) { int id = rear++; for(int i = 0; i < m; i++) { for(int j = 0; j < n; j++) W[id][i][j] = 0; } M[id] = m; N[id] = n; return id; } int mat_mul(int a, int b) { int id = New(M[a], N[b]); for(int i = 0; i < M[a]; i++) { for(int j = 0; j < N[b]; j++) { for(int k = 0; k < N[a]; k++) { W[id][i][j] = ((LL)W[a][i][k] * W[b][k][j] + W[id][i][j]) % mod; } } } return id; } int mat_pow(int a, int n) { int id = New(M[a], N[a]); for(int i = 0; i < M[a]; i++) W[id][i][i] = 1; while(n) { if(n & 1) id = mat_mul(id, a); a = mat_mul(a, a); n >>= 1; } return id; } int m, n, r, A, B; int U(int x, int y) { return x * (1 << m) + y; } void DFS(int x, int y, int z, int c) { if(c == m) { W[A][U(y, z)][U(x, y)] = 1; return; } for(int s = 0; s < 8; s++) { int nx = x << 1, ny = y << 1, nz = z << 1; if((s & 1) && ((nz & 2) || (ny & 4))) continue; if((s & 2) && ((nx & 4) || (nz & 4))) continue; if((s & 4) && ((nx & 2) || (ny & 4))) continue; if(s & 1) nx |= 1; if(s & 2) ny |= 1; if(s & 4) nz |= 1; DFS(nx, ny, nz, c + 1); } } int main() { int T; //FIN; scanf("%d", &T); while(T--) { scanf("%d%d", &m, &n); r = 1 << (2 * m); rear = 0; A = New(r, r); B = New(r, 1); DFS(0, 0, 0, 0); for(int i = 0; i < (1 << m); i++) W[B][i][0] = 1; B = mat_mul(mat_pow(A, n - 1), B); LL ans = 0; for(int i = 0; i < r; i++) { ans = (ans + W[B][i][0]) % mod; } printf("%I64d\n", ans); } return 0; }