zoukankan      html  css  js  c++  java
  • BZOJ 2973 石头游戏(矩阵构造,矩阵快速幂)

    时间限制: 1 Sec  内存限制: 128 MB
    提交: 5  解决: 4
    [提交] [状态] [命题人:admin]

    题目描述

    石头游戏在一个 n 行 m 列 (1≤n,m≤8) 的网格上进行,每个格子对应一种操作序列,操作序列至多有10种,分别用0~9这10个数字指明。
    操作序列是一个长度不超过6且循环执行、每秒执行一个字符的字符串。每秒钟,所有格子同时执行各自操作序列里的下一个字符。序列中的每个字符是以下格式之一:
    数字0~9:表示拿0~9个石头到该格子。
    NWSE:表示把这个格子内所有的石头推到相邻的格子,N表示上方,W表示左方,S表示下方,E表示右方。
    D:表示拿走这个格子的所有石头。
    给定每种操作序列对应的字符串,以及网格中每个格子对应的操作序列,求石头游戏进行了 t 秒之后,石头最多的格子里有多少个石头。在游戏开始时,网格是空的。

    输入

    第一行4个整数n, m, t, act。
    接下来n行,每行m个字符,表示每个格子对应的操作序列。
    最后act行,每行一个字符串,表示从0开始的每个操作序列。

    输出

    一个整数:游戏进行了t秒之后,所有方格中最多的格子有多少个石头。

    样例输入

    1 6 10 3
    011112
    1E
    E
    0
    

    样例输出

    3
    

    提示

    这是另一个类似于传送带的结构。左边的设备0间隔地产生石头并向东传送。设备1向右传送,直到设备2。10秒后,总共产生了5个石头,2个在传送带上,3个在最右边。

     
     
    将$n*m$个格子的状态转化为一个$(1,n*m)$的矩阵,然后构造$(n*m+1,n*m+1)$的转移矩阵。
    操作的长度最多为6,1~6的最小公倍数为60,所以60次操作为一组。$t = q*60+r$ ,用快速幂求出$q*60$的转移,然后连乘剩下$r$的。
     
    $F_t = F_0 * A^q* prod_{i=1}^{r} A_i$,其中$A = prod_{i=1}^{60} A_i$
     
    #include "bits/stdc++.h"
    
    using namespace std;
    typedef long long ll;
    const int mod = 1e9 + 7;
    const int maxn = 1e5 + 100;
    struct martix {
        ll a[100][100];
    };
    int n, m;
    martix F, aa[100];
    int mp[100][100];
    char opt[100][100];
    
    martix mul(martix a, martix b) {
        martix ret;
        for (int i = 0; i <= n * m; i++) {
            for (int j = 0; j <= n * m; j++) {
                ret.a[i][j] = 0;
                for (int k = 0; k <= n * m; k++) {
                    ret.a[i][j] += a.a[i][k] * b.a[k][j];
                }
            }
        }
        return ret;
    }
    
    martix powmod(martix a, int b) {
        martix ret;
        for (int i = 0; i <= n * m; i++) {
            for (int j = 0; j <= n * n; j++) {
                ret.a[i][j] = 0;
            }
            ret.a[i][i] = 1;
        }
        while (b) {
            if (b & 1) ret = mul(ret, a);
            a = mul(a, a);
            b >>= 1;
        }
        return ret;
    }
    
    int main() {
        //freopen("in.txt", "r", stdin);
        int t, act;
        scanf("%d %d %d %d", &n, &m, &t, &act);
        int to = 0;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                scanf("%1d", &mp[i][j]);
                to = max(to, mp[i][j]);
            }
        }
        for (int i = 0; i <= to; i++) {
            scanf("%s", opt[i]);
        }
        martix A, temp;
        memset(A.a, 0, sizeof(A.a));
        memset(F.a, 0, sizeof(F.a));
        memset(temp.a, 0, sizeof(temp.a));
        for (int i = 0; i < 90; i++) {
            temp.a[i][i] = 1;
            F.a[i][i] = 1;
            A.a[i][i] = 1;
        }
        int pp, dd;
        pp = t / 60;
        dd = t % 60;
        for (int i = 0; i < 60; i++) {
            memset(aa[i].a, 0, sizeof(aa[i].a));
            aa[i].a[0][0] = 1;
            for (int j = 1; j <= n; j++) {
                for (int k = 1; k <= m; k++) {
                    char op = opt[mp[j][k]][i % strlen(opt[mp[j][k]])];
                    if (op >= '0' && op <= '9') {
                        aa[i].a[0][(j - 1) * m + k] = op - '0';
                        aa[i].a[(j - 1) * m + k][(j - 1) * m + k] = 1;
                    } else if (op == 'N' && j > 1) {
                        aa[i].a[(j - 1) * m + k][(j - 2) * m + k] = 1;
                    } else if (op == 'W' && k > 1) {
                        aa[i].a[(j - 1) * m + k][(j - 1) * m + k - 1] = 1;
                    } else if (op == 'S' && j < n) {
                        aa[i].a[(j - 1) * m + k][j * m + k] = 1;
                    } else if (op == 'E' && k < m) {
                        aa[i].a[(j - 1) * m + k][(j - 1) * m + k + 1] = 1;
                    }
                }
            }
            A = mul(A, aa[i]);
            if (i < dd)
                temp = mul(temp, aa[i]);
        }
        F = mul(F, powmod(A, pp));
        F = mul(F, temp);
        ll ans = 0;
        for (int i = 1; i <= n * m; i++) {
            ans = max(ans, F.a[0][i]);
        }
        printf("%lld
    ", ans);
        return 0;
    }
  • 相关阅读:
    c++ 的几种强制转换的讨论
    观察者模式
    epoll实现linux进程通信
    vim 实现 go to definition的功能
    svn 的使用
    makefile文件的技术
    [转]epoll技术
    [转]poll技术
    Linux重定向的理解
    避免僵死进程的方法
  • 原文地址:https://www.cnblogs.com/albert-biu/p/10746828.html
Copyright © 2011-2022 走看看