zoukankan      html  css  js  c++  java
  • LA 3704细胞自动机——循环矩阵&&矩阵快速幂

    题目

    一个细胞自动机包含 $n$ 个格子,每个格子的取值为 $0 sim m-1$。给定距离 $d$,则每次操作是将每个格子的值变为到它的距离不超过 $d$ 的所有格子的在操作之前的值的和除以 $m$ 的余数。给出 $n, m, d, k$ 和自动机各个格子的初始值。你的任务是计算 $k$ 次操作以后各格子的值。($1 leq nleq 500, 1 leq mleq 10^6, 0 leq dleq n/2, 1leq kleq 10^7$).

    分析

    如果我们把 $t$ 次操作以后的各格子值写成列向量 $v_t$,不难发现 $v_{t+1}$ 的每一维都是 $v_t$ 中各维的线性组合,其中的加法和乘法都是在模 $m$ 的剩余系中完成。

    每次操作相当于乘以一个 $n imes n $ 矩阵,直接使用矩阵快速幂的复杂度为 $O(n^3logk)$,

    由于这里的矩阵比较特殊,是循环矩阵(从第二行开始每一行都是上一行循环右移),

    可以证明,两个循环矩阵的乘积仍然为循环矩阵。

    因此在存储时只需保存第一行,而计算矩阵乘法时也只需算出第一行即可。这样,矩阵乘法的时间复杂度降为 $O(n^2)$。总时间降为 $O(n^2log k)$,可以承受。

    用FFT优化的话可做到 $0(nlognlogk)$.  

    $$egin{bmatrix}
    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
    end{bmatrix} imes
    egin{bmatrix}
    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
    end{bmatrix} =
    egin{bmatrix}
    3 & 2 & 1 & 1 & 2\
    2 & 3 & 2 & 1 & 1\
    1 & 2 & 3 & 2 & 1\
    1 & 1 & 2 & 3 & 2\
    2 & 1 & 1 & 2 & 3
    end{bmatrix}$$

    #include<cstdio>
    #include<cstring>
    using namespace std;
    
    typedef long long ll;
    const int maxn = 500+10;
    struct matrix
    {
        int n;
        ll mat[maxn];
        matrix(){
            memset(mat, 0, sizeof(mat));
        }
    };
    ll n, p, d, k;
    ll a[maxn];
    
    matrix mul(matrix A, matrix B)   //矩阵相乘,这里A=B,且都是n x n的方阵
    {
        matrix ret;
        ret.n = A.n;
        for(int i = 0;i < A.n;i++)
            for(int j = 0;j < B.n;j++)  ret.mat[i] = (ret.mat[i] +  A.mat[j] * B.mat[(j-i+A.n)%A.n]) % p;
        return ret;
    }
    
    matrix mpow(matrix A, int n)
    {
        matrix ret;
        ret.n = A.n;
        ret.mat[0]=1;
        while(n)
        {
            if(n & 1)  ret = mul(ret, A);
            A = mul(A, A);
            n >>= 1;
        }
        return ret;
    }
    
    int  main()
    {
        while(scanf("%lld%lld%lld%lld", &n, &p,&d, &k) == 4)
        {
            for(int i = 0;i < n;i++)  scanf("%lld", &a[i]);
            matrix A;
            A.n = n;
            for(int i = 0;i <= d;i++) A.mat[i] = 1;
            for(int i = n-d; i < n;i++)  A.mat[i] = 1;
    
            A = mpow(A, k);
    
            for(int i = 0;i < A.n;i++)
            {
                ll tmp = 0;
                for(int j = 0;j < A.n;j++)  tmp = (tmp + A.mat[(j-i+n) % n] * a[j]) % p;
                printf("%lld%c", tmp, i == n-1 ? '
    ' : ' ');
            }
        }
        return 0;
    }

    记得开 long long !!

    参考链接: https://vjudge.net/status/#un=&OJId=UVALive&probNum=3704&res=0&orderBy=run_id&language=

  • 相关阅读:
    pymssql连接Azure SQL Database
    Python升级后ssl模块不可用问题解决和浅析
    CentOS 7升级Python到3.6.6后yum出错问题解决总结
    Python监控SQL Server数据库服务器磁盘使用情况
    fastjason常用方法
    类型擦除真的能完全擦除一切信息吗?java 泛型揭秘
    spring boot打包成war包的页面该放到哪里?
    为什么delete后磁盘空间没有释放而truncate会释放?
    leetcode 977. Squares of a Sorted Array
    leetcode 844. Backspace String Compare
  • 原文地址:https://www.cnblogs.com/lfri/p/11474049.html
Copyright © 2011-2022 走看看