• 牛客1024B 石头游戏


    题目描述

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

    输入描述:

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

    输出描述:

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

    示例1

    输入

    1 6 10 3
    011112
    1E
    E
    0

    输出

    3

    说明

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

    题解

    很有思维难度的一个题目。但是这题无论哪里都没有给出(T)的数据范围,这谁看的出来是矩阵快速幂啊...
    将当前矩阵写成一个一维向量,并且钦定(f[0]=1),那么(i*(m-1)+j)代表的就是原来位置((i,j))的石头数量。
    因为操作序列长度小于等于(6),而(gcd(1,2,3,4,5,6)=60),也就是说每个操作序列在重复(60)次后都一定会回到位置(1)。那么可以把(T)分成(lfloor frac T {60} floor)(Tmod 60)两部分。
    构造(c[pos])表示第(pos)次操作的转移矩阵。(这里用((i,j))表示坐标((i,j))在一维向量中的位置)

    • 当操作(s[i])为数字,(c[pos][0,(i,j)]=s[i])(c[pos][(i,j),(i,j)]=1)
    • 当操作(s[i]=S,E,W,N)时,设移动后的位置为((x,y))(c[pos][(i,j),(x,y)]=1)
    • 当操作(s[i]=D)时,(c[pos][(i,j),(i,j)]=0)

    (C=prod _{i=1}^{60} c_i)(r=T mod 60),那么答案即为(f*C*prod _{i=1}^r c_r)

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int N = 110;
    
    ll T;
    int n, m, lim, len[N], act, now[10][10];
    char s[10][10], t[10][10];
    
    struct mat {
        ll a[65][65];
        mat() {memset(a, 0, sizeof(a));}
        mat operator * (mat &x) {
            mat ans;
            for(int i = 0; i <= lim; ++i) 
                for(int j = 0; j <= lim; ++j) 
                    for(int k = 0; k <= lim; ++k) 
                        ans.a[i][j] += a[i][k] * x.a[k][j];
            return ans;
        }
        mat Pow(ll t, mat a) {
            mat ans; ans.a[0][0] = 1;
            while(t) {
                if(t & 1) ans = ans * a;
                a = a * a; t >>= 1;
            }
            return ans;
        }
    }c[61], C;
    
    int idx(int x, int y) {return (x - 1) * m + y;}
    
    void print(mat x, bool flag) {
    	puts("#####################");
    	if(flag) {
    		for(int i = 0; i <= lim; ++i) printf("%lld ", x.a[0][i]);
    		puts("");
    		return;
    	}
    	for(int i = 0; i <= lim; ++i) {
    		printf("%d: ", i);
    		for(int j = 0; j <= lim; ++j) {
    			printf("%lld ", x.a[i][j]);
    		}
    		puts("");
    	}
    	puts("#####################");
    }
    
    int main() {
        scanf("%d%d%lld%d", &n, &m, &T, &act);
        lim = n * m;
        for(int i = 1; i <= n; ++i) {
            scanf("%s", t[i] + 1);
            for(int j = 1; j <= m; ++j) t[i][j] -= '0', ++t[i][j];
        }
        for(int i = 1; i <= act; ++i) {
            scanf("%s", s[i] + 1);
            len[i] = strlen(s[i] + 1);
        }
        for(int pos = 1; pos <= 60; ++pos) {
            c[pos].a[0][0] = 1;
            for(int i = 1; i <= n; ++i) {
                for(int j = 1; j <= m; ++j) {
    //              putchar(s[t[i][j]][now[i][j]]);
                    now[i][j] = (now[i][j] % len[t[i][j]]) + 1;
                    if(s[t[i][j]][now[i][j]] >= '0' && s[t[i][j]][now[i][j]] <= '9') {
                        c[pos].a[0][idx(i, j)] = s[t[i][j]][now[i][j]] - '0';
                        c[pos].a[idx(i, j)][idx(i, j)] = 1;
                    } else {
                        if(s[t[i][j]][now[i][j]] == 'D') c[pos].a[idx(i, j)][idx(i, j)] = 0;
                        if(i > 1 && s[t[i][j]][now[i][j]] == 'N') 
    						c[pos].a[idx(i, j)][idx(i - 1, j)] = 1;
                        if(i < n && s[t[i][j]][now[i][j]] == 'S') 
    						c[pos].a[idx(i, j)][idx(i + 1, j)] = 1;
                        if(j > 1 && s[t[i][j]][now[i][j]] == 'W') 
    						c[pos].a[idx(i, j)][idx(i, j - 1)] = 1;
                        if(j < m && s[t[i][j]][now[i][j]] == 'E') 
    						c[pos].a[idx(i, j)][idx(i, j + 1)] = 1;
                    }
                }
            }
    //        puts("");
        }
        C = c[1];
        for(int pos = 2; pos <= 60; ++pos) C = C * c[pos];
        C = C.Pow(T / 60, C);
        for(int pos = 1; pos <= T % 60; ++pos) {
    //    	printf("Round # %d
    ", pos);
    		C = C * c[pos];
    //		print(c[pos], 0);
    //		printf("The test # %d
    ", pos);
    //		print(C, 1);
    	}
        ll ans = 0;
        for(int i = 1; i <= lim; ++i) ans = max(ans, C.a[0][i]);
        printf("%lld
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    1101-Trees on the Level
    1099-移动小球
    1096-组合数
    Windows环境配置Apache+Mysql+PHP
    ArtDialog简单使用示例
    实现数字与字母的随机数
    SQLServer2005:在执行批处理时出现错误。错误消息为: 目录名无效
    sql语句总结
    在SQL SErver中实现数组功能
    aspnet_regiis.exe 的用法
  • 原文地址:https://www.cnblogs.com/henry-1202/p/11469114.html
Copyright © 2020-2023  润新知