Poj 3150

slove

将 $t$ 次操作后的各格子写成矩阵 $v_t$, 那么 $v_{t+1}$ 的每一维都是 $v_t$ 中的各

维的线性组合,可以利用矩阵乘法,设 $v_{t+1} = Av_t$, 当 $d = 1$ 时,有
$$A =
\left[
\begin{matrix}
1 & 1 & 0 & \dots & 0 & 1 \\
1 & 1 & 1 & 0 & \dots & 0 \\
0 & 1 & 1 & 1 & 0 & \dots \\
\dots & 0 & 1 & 1 & 1 & 0 \\
1 & \dots & 0 & 0 & 1 & 1 \\
1 & 1 & \dots & 0 & 0 & 1 \\
\end{matrix}
\right]
$$

最终答案 $v_k = A^kv_0$, $v_0$ 为初始矩阵,时间复杂度为 $O(n^3logk)$,显然这样的

时间复杂度是无法承受的,观察矩阵 $A$, $A$ 的一个特征是知道该矩阵的第一行就可以知

道该矩阵,这是一个循环矩阵,循环矩阵的矩阵乘法的时间复杂度为 $O(n^2logk)$,这样的时

间复杂度是可以接受的。
这里做矩阵乘法时运用数组的 $0$ 位置方便理解。

#include <iostream>
#include <cstdio>
#include <cstring>

const int N = 510;

#define LL long long

LL A[N], B[N], C[N], T[N];
int n, M, d, k;

void Mul(LL *a, LL *b, LL *c) {
    memset(T, 0, sizeof T);
    for(int i = 0; i < n; i ++)
        for(int j = 0; j < n; j ++) {
            if(i - j >= 0) T[i] = (T[i] + (a[j] * b[i - j]) % M) % M;
            else T[i] = (T[i] + (a[j] * b[i - j + n]) % M) % M;
        }
    for(int i = 0; i < n; i ++) c[i] = T[i];
}

void Ksm() {
    while(k) {
        if(k & 1) Mul(B, A, B); // B = B * A;
        Mul(A, A, A); // A = A * A;
        k >>= 1;
    }
}

int main() {
    std:: cin >> n >> M >> d >> k;
    for(int i = 0; i < n; i ++) std:: cin >> C[i];
    for(int i = 0; i <= d; i ++) A[i] = 1;
    for(int i = n - 1; i >= n - d; i --) A[i] = 1;
    B[0] = 1;
    Ksm();
    Mul(B, C, C);
    for(int i = 0; i < n; i ++) std:: cout << C[i] << " ";
    return 0;
}

 

posted @ 2018-06-25 19:46  qmey  阅读(83)  评论(0编辑  收藏  举报