题目描述
石头游戏在一个 行 列 的网格上进行,每个格子对应一种操作序列,操作序列至多有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; }