Leetcode 957. Prison Cells After N Days 两种方法实现(找循环节 and 矩阵快速幂)

题意

  • 给你一个 m m m长的 0 0 0 1 1 1序列,然后给你一种递推规则,问你递推 n n n次之后这个序列变成什么形式
  • 递推规则就是第 i i i个位置 a ( i ) a(i) a(i)设置为 1 1 1,当 a ( i − 1 ) = a ( i + 1 ) a(i-1) = a(i+1) a(i1)=a(i+1),否则为 0 0 0;两端的位置变换之后一定为 0 0 0
  • 数据范围: m = 8 m = 8 m=8, n ≤ 1 0 9 n \le 10^9 n109

思路1(循环节):

  • 这个题难度就在 n n n很大
  • 不过我们很容易发现 8 8 8位长的2进制序列至多有 2 8 2^8 28种状态,因此当 n n n很大时,递推过程中一定存在重复,也就是说会有循环节,所以我们只要发现循环节,很容易求解这个问题

思路2(矩阵快速幂):

  • 但刚才说的这种方法只适用于 m m m很小的情况,如果 m m m很大就无法使用了
  • 另一个思路,我们可以从递推的角度来看这个问题,如果我们能找到合适的递推数学表达形式,进一步我们就可以通过矩阵快速幂来求解这个问题了
  • 根据上述规则,我们可以有如下递推公式
    a i t = ( a i − 1 t − 1 + a i + 1 t − 1 + 1 )    mod    2 , if i > 0    a n d    i < m − 1 a^t_i = (a^{t-1}_{i-1} + a^{t-1}_{i+1} + 1) \; \text{mod} \; 2, \quad \text{if} \quad i \gt 0 \; and \; i \lt m - 1 ait=(ai1t1+ai+1t1+1)mod2,ifi>0andi<m1
    a i t = 0    mod    2 , if i = 0    o r    i = m − 1 a^t_i = 0 \; \text{mod} \; 2, \quad \text{if} \quad i = 0 \; or \; i = m - 1 ait=0mod2,ifi=0ori=m1
  • 根据这个递推公式,我们可以给出一个矩阵运算的递推式:
    x t = A x t − 1 x^t = Ax^{t-1} xt=Axt1
  • 其中 x x x是把 a a a变成一个列向量,并在最后加一维 1 1 1,所以 x x x m + 1 m+1 m+1维的
  • A A A m + 1 × m + 1 m+1 \times m+1 m+1×m+1维的矩阵,具体每维的值定义如下:
    A ( i − 1 , i + 1 ) = 1 , if i > 0    a n d    i < m − 1 A ( i , m ) = 1 , if i = 0    o r    i = m − 1 A ( i , j ) = 0 , o t h e r w i s e A(i-1, i+1) = 1, \quad \text{if} \quad i \gt 0 \; and \; i \lt m - 1\\ A(i, m) = 1, \quad \text{if} \quad i = 0 \; or \; i = m - 1\\ A(i, j) = 0, \quad otherwise A(i1,i+1)=1,ifi>0andi<m1A(i,m)=1,ifi=0ori=m1A(i,j)=0,otherwise
  • 因此, x n = A n × x 0    mod    2 x^n = A^n \times x^0 \; \text{mod} \; 2 xn=An×x0mod2, 然后我们可以利用矩阵快速幂进行求解了。
  • 最后时间复杂度: O ( m 3 log ⁡ n ) O(m^3 \log n) O(m3logn)

实现1(循环节)

class Solution {
public:
    static const int NUM = 8;
    void to_vector(const bitset<NUM>& x, vector<int>& out){
        for (int i = 0; i < NUM; i++){
            out.push_back(x[i]);
        }
    }
    void to_bitset(const vector<int>& x, bitset<NUM>& out){
        for (int i = 0; i < x.size(); i++){
            out[i] = x[i];
        }
    }
    bitset<NUM> transfer(const bitset<NUM> st){
        bitset<NUM> next;
        next[0] = 0;
        next[NUM - 1] = 0;
        for (int i = 1; i < NUM - 1; i++){
            if (st[i-1] == st[i+1]){
                next[i] = 1;
            }
            else{
                next[i] = 0;
            }
        }
        return next;
    }
    vector<int> prisonAfterNDays(vector<int>& cells, int N) {
        bitset<NUM> st;
        unordered_map<bitset<NUM>, int> mapp;
        unordered_map<int, bitset<NUM>> rmapp;
        to_bitset(cells, st);
        int len = -1, pre = -1;
        for (int i = 0; i < N; i++){
            if (mapp.find(st) != mapp.end()){
                int idx = mapp[st];
                len = i - mapp[st];
                pre = mapp[st];
                break;
            }
            mapp[st] = i;
            rmapp[i] = st;
            st = transfer(st);
        }
        vector<int> ans;
        if (len == -1){
            to_vector(st, ans);
            return ans;
        }
        int now = (N - pre + 1) % len;
        if (now == 0){
            to_vector(rmapp[pre + len - 1], ans);
            return ans;
        }
        to_vector(rmapp[pre + now - 1], ans);
        return ans;
    }
};

实现2(矩阵快速幂)

class Solution {
public:
    static const int NUM = 8;
    typedef vector<int> vec;
    typedef vector<vec> mat;
    mat matmul(const mat& A, const mat& B){
	    mat C(A.size(), vec(B[0].size()));
	    for (int i = 0; i < A.size(); i++){
		    for (int k = 0; k < B.size(); k++){
			    for (int j = 0; j < B[0].size(); j++){
				    C[i][j] += A[i][k] * B[k][j];
                    C[i][j] %= 2;
			    }
		    }
	    }   
	    return C;
    }
    mat tomat(vec& A){
        mat B(A.size(), vec(1));
        for (int i = 0; i < A.size(); i++){
            B[i][0] = A[i];
        }
        return B;
    }
    mat matpow(const mat& A, int n){
        mat ans(A.size(), vec(A[0].size(), 0));
        for (int i = 0; i < ans.size(); i++)
            ans[i][i] = 1;
        mat tmp(A);
        while (n > 0){
            if (n & 1){
                ans = matmul(ans, tmp);
            }
            tmp = matmul(tmp, tmp);
            n>>=1;
        }
        return ans;
    }
    vector<int> prisonAfterNDays(vector<int>& cells, int N) {
        mat A(cells.size() + 1, vec(cells.size() + 1));
        *(A.rbegin()->rbegin()) = 1;
        for (int i = 1; i < cells.size() - 1; i++){
            A[i][i-1] = 1;
            A[i][i+1] = 1;
            *A[i].rbegin() = 1;
        }
        cells.push_back(1);
        auto x = tomat(cells);
        A = matpow(A, N);
        x = matmul(A, x);
        vec ans;
        for (int i = 0; i < cells.size() - 1; i++){
            ans.push_back(x[i][0]);
        }
        return ans;
    }
};

你可能感兴趣的:(ACM_矩阵快速幂)