POJ 3150 Cellular Automaton(矩阵快速幂+特殊矩阵的性质)

题目的意思开始没看懂,看了别人的博客的翻译

题目大意:一个元胞中包含若干细胞,每个细胞都有初始value值,题目定义了一个细胞距离,细胞i、j之间的距离d=min(|i-j|,n-|i-j|),称
与细胞i距离不超过d的所有细胞(包括该细胞本身)的集合为细胞i的d-environment,经过一个d-steps变换后,元胞中每一个细胞的值变
为该细胞d-environment内所有细胞value值总和模上m,最后求经过k个d-steps变换后,元胞中每个细胞的最终值。

思路:

可以用矩阵相乘来表示这种step变化,每次变化乘上的矩阵是A:(比如d=1)

[1, 1, 0, 0, 1]
[1, 1, 1, 0, 0]
[0, 1, 1, 1, 0]
[0, 0, 1, 1, 1]
[1, 0, 0, 1, 1]

所以A^k求出以后再乘上细胞的value矩阵便可

不过仅仅是这样还会超时,必须利用这个矩阵的性质

比如A^3=

[7, 6, 4, 4, 6]
[6, 7, 6, 4, 4]
[4, 6, 7, 6, 4]
[4, 4, 6, 7, 6]
[6, 4, 4, 6, 7]

任然具有每行错开一位的性质,可以证明始终有这种性质

所以只需求出第一行便可,复杂度从n^3降到n^2

//8132K	3532MS
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define ll long long

int n,mod,d,k;

struct mat{
    int a[505][505];
    void ini(){
        memset(a,0,sizeof(a));
    }
};
mat cell,step,ans,tans;
mat mul(mat &m1,mat &m2){
    mat ans;
    ans.ini();
    for(int j=1;j<=n;j++)
        if(m1.a[1][j])
            for(int k=1;k<=n;k++)
                ans.a[1][k]=((ll)ans.a[1][k]+(ll)m1.a[1][j]*(ll)m2.a[j][k])%(ll)mod;
    for(int i=2;i<=n;i++)
    for(int j=1;j<=n;j++)
        ans.a[i][j]=ans.a[1][(n+j-i)%n+1];
    return ans;
}

void print(mat &m){ //debug
    puts("");
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            printf("%d%c",m.a[i][j],j==n?'\n':' ');

}
int main(){
    scanf("%d%d%d%d",&n,&mod,&d,&k);
    for(int i=1;i<=n;i++)
        scanf("%d",&cell.a[i][1]);

    for(int i=1;abs(i-1)<=d;i++){
        step.a[1][i]=1;
        step.a[1][(n-i+1)%n+1]=1;
    }
    for(int i=2;i<=n;i++)
        for(int j=1;j<=n;j++)
            step.a[i][j]=step.a[1][(n+j-i)%n+1];

    for(int i=1;i<=n;i++)
        tans.a[i][i]=1;

    while(k){
        if(k&1) tans=mul(tans,step);
        step=mul(step,step);
        k>>=1;
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(tans.a[i][j])
            ans.a[i][1]=((ll)ans.a[i][1]+(ll)tans.a[i][j]*(ll)cell.a[j][1])%(ll)mod;

    for(int i=1;i<=n;i++)
        printf("%d%c",ans.a[i][1],i==n? '\n':' ');
    return 0;
}



以下是Java解决POJ3233—矩阵幂序列问题的代码和解释: ```java import java.util.Scanner; public class Main { static int n, k, m; static int[][] A, E; public static void main(String[] args) { Scanner sc = new Scanner(System.in); n = sc.nextInt(); k = sc.nextInt(); m = sc.nextInt(); A = new int[n][n]; E = new int[n][n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { A[i][j] = sc.nextInt() % m; E[i][j] = (i == j) ? 1 : 0; } } int[][] res = matrixPow(A, k); int[][] ans = matrixAdd(res, E); printMatrix(ans); } // 矩阵乘法 public static int[][] matrixMul(int[][] a, int[][] b) { int[][] c = new int[n][n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { for (int k = 0; k < n; k++) { c[i][j] = (c[i][j] + a[i][k] * b[k][j]) % m; } } } return c; } // 矩阵快速幂 public static int[][] matrixPow(int[][] a, int b) { int[][] res = E; while (b > 0) { if ((b & 1) == 1) { res = matrixMul(res, a); } a = matrixMul(a, a); b >>= 1; } return res; } // 矩阵加法 public static int[][] matrixAdd(int[][] a, int[][] b) { int[][] c = new int[n][n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { c[i][j] = (a[i][j] + b[i][j]) % m; } } return c; } // 输出矩阵 public static void printMatrix(int[][] a) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { System.out.print(a[i][j] + " "); } System.out.println(); } } } ``` 解释: 1. 首先读入输入的n、k、m和矩阵A,同时初始化单位矩阵E。 2. 然后调用matrixPow函数求出A的k次幂矩阵res。 3. 最后将res和E相加得到结果ans,并输出。 4. matrixMul函数实现矩阵乘法,matrixPow函数实现矩阵快速幂matrixAdd函数实现矩阵加法,printMatrix函数实现输出矩阵
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值