快速矩阵幂 Gym100827F Knights

传送门:点击打开链接

题意:在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;
}


你可能感兴趣的:(快速矩阵幂 Gym100827F Knights)