题解 | 石头游戏

石头游戏

https://ac.nowcoder.com/acm/contest/1024/B

题目描述

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

输入描述:

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

输出描述:

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

示例1

输入

1 6 10 3
011112
1E
E
0

输出

3

说明

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

题解

很有思维难度的一个题目。~~但是这题无论哪里都没有给出的数据范围,这谁看的出来是矩阵快速幂啊...~~
将当前矩阵写成一个一维向量,并且钦定,那么代表的就是原来位置的石头数量。
因为操作序列长度小于等于,而,也就是说每个操作序列在重复次后都一定会回到位置。那么可以把分成两部分。
构造表示第次操作的转移矩阵。(这里用表示坐标在一维向量中的位置)

  • 当操作为数字,
  • 当操作时,设移动后的位置为
  • 当操作时,

,那么答案即为

#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\n", pos);
        C = C * c[pos];
//        print(c[pos], 0);
//        printf("The test # %d\n", pos);
//        print(C, 1);
    }
    ll ans = 0;
    for(int i = 1; i <= lim; ++i) ans = max(ans, C.a[0][i]);
    printf("%lld\n", ans);
    return 0;
}
全部评论

相关推荐

12-24 14:26
东北大学 Java
一只乌鸦:重邮+东北,好经典的学校
最后再改一次简历
点赞 评论 收藏
分享
12-08 16:04
门头沟学院 Java
本人本科末9,今年大三。大一大二一直玩,什么都没学到,在大学混日子混了两年,每天不是在打农就是在steam。大三开学时一个和自己玩的好的同学去实习了,才发现自己白白浪费了两年的时间,如果真不冲一下就真去京东,阿里,美团送外卖了今年9月份开始学Java,一开始一直跟着黑马视频看,后面发现看视频效率太低了,时间根本不够,就开始主要看文档和看书了。这几个月一直在学,真的尽力了,希望暑期前能找一份好点的实习。我简历上面的项目大多没有指标,但是实际上我是真没多少时间去做项目,我基本主要是动手只做了外卖和天机,黑马点评和12306我都是只是看了项目。主要是自己的时间真的不多,但是这样子自己的代码能力确实比较差。而且自己也没有做过实际的工程,我顶多用jmeter测试一下接口tps啥的,比如使用Redis管道提升了一点性能,减少Redis交互,这种值得写上去吗?需不需要具体到某些数字求求各位佬给一些建议,看看简历怎么优化?项目介绍是不是不够详细?没有具体到业务方面。项目会不会提到大致实现原理导致面试官一看简历就知道怎么实现就没有问的欲望?专业技能一些字段是不是要加粗,是不是写太啰嗦了?有没有必要压缩内容变成一页?两页的话是不是都要把两页填地满满的。
给秋招一个交代:一页简历最好,网上做的项目放面试官眼里都是玩具,简历上不需要强调有什么难点,记住就行防止真的问。然后背八股,多投多面试就行
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务