返回顶部

AcWing - 206 - 石头游戏 = 矩阵快速幂

https://www.acwing.com/problem/content/208/

因为1~6的最小公倍数是60,所以以60为周期进行快速幂然后剩下的算余项,注意两点:

1、递推矩阵永远有这样的形式:

A=A*B

其中A就是用来把各步的递推结果压缩保存的矩阵(仿照快速幂)

2、越界的石子直接消失了,原题没说明要怎么处理
3、计算的过程会溢出

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int mod = 10000007;
struct Matrix {
    static const int MAXN = 65;
    ll ma[MAXN][MAXN];
    Matrix() {
        //init();
    }
    void init() {
        memset(ma, 0, sizeof(ma));
    }
    void setE() {
        init();
        for(int i = 0; i < MAXN; ++i)
            ma[i][i] = 1;
    }

    Matrix operator+(const Matrix &m)const {
        Matrix Tmp;
        Tmp.init();
        for(int i = 0; i < MAXN; ++i) {
            for(int j = 0; j < MAXN; ++j)
                Tmp.ma[i][j] = ma[i][j] + m.ma[i][j];
        }
        return Tmp;
    }

    Matrix operator*(const Matrix &m)const {
        Matrix Tmp;
        Tmp.init();
        for(int k = 0; k < MAXN; ++k) {
            for(int i = 0; i < MAXN; ++i) {
                register ll r = ma[i][k];
                for(int j = 0; j < MAXN; ++j)
                    Tmp.ma[i][j] += r * m.ma[k][j];
            }
        }
        return Tmp;
    }

    void show(int n) {
        for(int i = 0; i < n; ++i) {
            for(int j = 0; j < n; ++j) {
                printf("%2d ", ma[i][j]);
            }
            puts("");
        }
        puts("---");
    }
} tma[60], Tma, F;

Matrix qpow(Matrix x, ll n) {
    Matrix res;
    res.setE();
    while(n) {
        if(n & 1)
            res = res * x;
        x = x * x;
        n >>= 1;
    }
    return res;
}

char ins[8][9];
char ins2[10][7];

int n, m;

void _setins(int i, int j, int ti, char op) {
    if(op >= '0' && op <= '9') {
        tma[ti].ma[i * m + j][i * m + j] = 1;
        tma[ti].ma[i * m + j][n * m] = op - '0';
    } else if(op == 'D') {
        tma[ti].ma[i * m + j][i * m + j] = 0;
    } else if(op == 'N') {
        tma[ti].ma[i * m + j][i * m + j] = 0;
        if(i > 0) {
            tma[ti].ma[(i - 1)*m + j][i * m + j] = 1;
        }
    } else if(op == 'W') {
        tma[ti].ma[i * m + j][i * m + j] = 0;
        if(j > 0) {
            tma[ti].ma[i * m + j - 1][i * m + j] = 1;
        }
    } else if(op == 'S') {
        tma[ti].ma[i * m + j][i * m + j] = 0;
        if(i + 1 < n) {
            tma[ti].ma[(i + 1)*m + j][i * m + j] = 1;
        }
    } else {
        tma[ti].ma[i * m + j][i * m + j] = 0;
        if(j + 1 < m) {
            tma[ti].ma[i * m + j + 1][i * m + j] = 1;
        }
    }
}

void setins(int i, int j) {
    int insid = (ins[i][j] - '0');
    char *op = ins2[insid];
    int len = strlen(op);
    int cur = 0;
    for(int ti = 0; ti < 60; ++ti) {
        _setins(i, j, ti, op[cur]);
        ++cur;
        if(cur == len)
            cur = 0;
    }
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    ll T;
    int act;
    while(~scanf("%d%d%lld%d", &n, &m, &T, &act)) {
        for(int i = 0; i < n; ++i)
            scanf("%s", ins[i]);
        for(int a = 0; a < act; ++a) {
            scanf("%s", ins2[a]);
        }
        for(int i = 0; i < 60; ++i) {
            tma[i].init();
            tma[i].ma[n * m][n * m] = 1;
        }
        for(int i = 0; i < n; ++i) {
            for(int j = 0; j < m; ++j)
                setins(i, j);
        }

        /*for(int i = 0; i < 1; ++i) {
            tma[i].show(n * m + 1);
        }*/

        Tma.setE();
        for(int i = 0; i < 60; ++i)
            Tma = tma[i] * Tma;
        ll T1 = T / 60;
        Tma = qpow(Tma, T1);
        ll T2 = T % 60;
        for(int i = 0; i < T2; ++i) {
            Tma = tma[i] * Tma;
            //Tma.show(n * m + 1);
        }

        F.init();
        F.ma[n * m][0] = 1;
        //F.show(n * m + 1);

        F = Tma * F;

        //F.show(n * m + 1);
        ll maxans = 0;
        for(int i = 0; i < n * m; ++i) {
            maxans = max(maxans, F.ma[i][0]);
        }
        printf("%lld\n", maxans);
    }
}
posted @ 2019-09-18 18:01  Inko  阅读(185)  评论(0编辑  收藏  举报