石頭遊戲在一個 \(n\) 行 \(m\) 列 \((1\leq n,m \leq 8)(1≤n,m≤8)\) 的網格上進行,每一個格子對應一種操做序列,操做序列至多有10種,分別用0~9這10個數字指明。
操做序列是一個長度不超過6且循環執行、每秒執行一個字符的字符串。每秒鐘,全部格子同時執行各自操做序列裏的下一個字符。序列中的每一個字符是如下格式之一:
數字\(0\text{-}9\):表示拿\(0\text{-}9\)個石頭到該格子。
\(NWSE\):表示把這個格子內全部的石頭推到相鄰的格子,\(N\)表示上方,\(W\)表示左方,\(S\)表示下方,\(E\)表示右方。
\(D\):表示拿走這個格子的全部石頭。
給定每種操做序列對應的字符串,以及網格中每一個格子對應的操做序列,求石頭遊戲進行了 \(t\) 秒以後,石頭最多的格子裏有多少個石頭。在遊戲開始時,網格是空的。c++
第一行\(4\)個整數\(n, m, t, act\)。
接下來\(n\)行,每行\(m\)個字符,表示每一個格子對應的操做序列。
最後\(act\)行,每行一個字符串,表示從\(0\)開始的每一個操做序列。spa
一個整數:遊戲進行了\(t\)秒以後,全部方格中最多的格子有多少個石頭。code
1 6 10 3
011112
1E
E
0遊戲
3字符串
這是另外一個相似於傳送帶的結構。左邊的設備0間隔地產生石頭並向東傳送。設備1向右傳送,直到設備2。10秒後,總共產生了5個石頭,2個在傳送帶上,3個在最右邊。it
頗有思惟難度的一個題目。可是這題不管哪裏都沒有給出\(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}\rfloor\)和\(T\mod 60\)兩部分。
構造\(c[pos]\)表示第\(pos\)次操做的轉移矩陣。(這裏用\((i,j)\)表示座標\((i,j)\)在一維向量中的位置)class
設\(C=\prod _{i=1}^{60} c_i\),\(r=T \mod 60\),那麼答案即爲\(f*C*\prod _{i=1}^r c_r\)test
#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; }