牛客1024B 石頭遊戲

題目描述

石頭遊戲在一個 \(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

輸入

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

  • 當操做\(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\)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;
}
相關文章
相關標籤/搜索