题面:UVA1386 Cellular Automaton

矩阵乘法+快速幂解法:

这是一个比较裸的有点复杂需要优化的矩乘快速幂,所以推荐大家先做一下下列洛谷题目练练手:

(会了,差不多就是多倍经验题了)

注:如果你还不会矩阵乘法,可以移步了解一下P3390的题解

P1939 【模板】矩阵加速(数列)

P3390 【模板】矩阵快速幂

P1962 斐波那契数列

P4910 帕秋莉的手环

P4838 P哥破解密码

然后讲一下本题,读题我们发现这个环上所进行的 k 次操作都是一模一样的,还是相邻的数的和,于是想到用矩阵快速幂来写。

解题思路:

我们可以根据 d 的值来建出基础矩阵,举个例子(样例):

					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

这是样例每一次操作所对应的乘法矩阵。我们要求出 k 次操作后的环上的元素等同于乘以 k 次这个矩阵,而这个过程可以直接用快速幂优化成log复杂度。

于是我们便可以光明正大的提交,然后光荣 TLE 了

为什么呢?我们看到数据范围:$ n \leq 500 $ !众所周知:矩阵乘法中矩阵上每一个元素都会被用行乘列的方式更新,所以复杂度为 \(n^3\),在乘上快速幂的一个log n ,不TLE才怪!

优化方案:

于是我们尝试优化一下(把那个 $ n^3 $ 降到 $ n^2 $ ):我们再看到上面样例的矩阵,可以发现它的下一行等于上一行所有的 1 向右移一位。所以我们进行矩阵乘法时可以不更新矩阵的每一个位置,而是只更新它的第一行(将它压缩一下)其它几行可以通过第一行推出来。

例如:

					0 2 1 1 2

我们可以通过这一行推出整个矩阵(向右移一位):

					0 2 1 1 2
2 0 2 1 1
1 2 0 2 1
1 1 2 0 2
2 1 1 2 0

于是乎,我们写一个新的”矩阵乘法“代码如下:

void cheng(ll a[],ll b[]){
for(int i=1;i<=n;i++)//预处理 1
res[i]=0,s[1][i]=b[i];
for(int i=2;i<=n;i++){
s[i][1]=s[i-1][n];
for(int j=2;j<=n;j++)
s[i][j]=s[i-1][j-1];
}// 解压一维矩阵,复杂度不会变回 n^3!
for(int i=1;i<=n;i++)
for(int k=1;k<=n;k++)
res[i]+=(a[k]*s[i][k])%m,res[i]%=m;
for(int i=1;i<=n;i++)a[i]=res[i];
}// 本题专用“矩阵乘法”
//请不要直接给a数组赋值,不然后果自负!

然后在用快速幂优化一下:

while(k){
if(k&1)cheng(ans,base);
cheng(base,base);
k>>=1;
}

完整代码:

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm> #define ll long long
#define db double
#define inf 0x7fffffff using namespace std; const int l=501;
int n,m,d,k;
ll s[l][l];
ll ans[l],base[l],res[l];
// ans=(answer),base(基础矩阵),res=(result)
// s数组是用来解压矩阵的(将一维矩阵换成二维) inline ll qr(){
char ch;
while((ch=getchar())<'0'||ch>'9');
ll res=ch^48;
while((ch=getchar())>='0'&&ch<='9')
res=(res<<1)+(res<<3)+(ch^48);
return res;
} void cheng(ll a[],ll b[]){
for(int i=1;i<=n;i++)//预处理 1
res[i]=0,s[1][i]=b[i];
for(int i=2;i<=n;i++){
s[i][1]=s[i-1][n];
for(int j=2;j<=n;j++)
s[i][j]=s[i-1][j-1];
}// 解压一维矩阵,复杂度不会变回 n^3!
for(int i=1;i<=n;i++)
for(int k=1;k<=n;k++)
res[i]+=(a[k]*s[i][k])%m,res[i]%=m;
for(int i=1;i<=n;i++)a[i]=res[i];
}// 本题专用“矩阵乘法”
//请不要直接给a数组赋值,不然后果自负! int main(){
while(scanf("%d%d%d%d",&n,&m,&d,&k)!=EOF){
for(int i=1;i<=n;i++)//预处理 2
ans[i]=qr(),base[i]=0;
for(int i=0;i<=d;i++)//单位矩阵
base[1+i]=base[(n-i)%n+1]=1;
while(k){
if(k&1)cheng(ans,base);
cheng(base,base);
k>>=1;
}// 只有四行的快速幂
for(int i=1;i<n;++i){
printf("%lld ",ans[i]);
}printf("%lld\n",ans[n]);
}
return 0;
} //预处理 1:将res数组归零,将b数组赋值给s数组第一维以便压缩 //预处理 2:给ans数组赋初值,将单位矩阵清零

注:解压矩阵会消耗很多时间,也可以不解压,但乘起来会有些麻烦(蒟蒻手残,就不压行了吧)。

UVA1386 【Cellular Automaton】题解的更多相关文章

  1. 【POJ】3150 Cellular Automaton(矩阵乘法+特殊的技巧)

    http://poj.org/problem?id=3150 这题裸的矩阵很容易看出,假设d=1,n=5那么矩阵是这样的 1 1 0 0 1 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 ...

  2. UVA 1386 - Cellular Automaton(循环矩阵)

    UVA 1386 - Cellular Automaton option=com_onlinejudge&Itemid=8&page=show_problem&category ...

  3. [POJ 3150] Cellular Automaton (矩阵高速幂 + 矩阵乘法优化)

    Cellular Automaton Time Limit: 12000MS   Memory Limit: 65536K Total Submissions: 3048   Accepted: 12 ...

  4. POJ 3150 Cellular Automaton(矩阵快速幂)

    Cellular Automaton Time Limit: 12000MS Memory Limit: 65536K Total Submissions: 3504 Accepted: 1421 C ...

  5. POJ - 3150 :Cellular Automaton(特殊的矩阵,降维优化)

    A cellular automaton is a collection of cells on a grid of specified shape that evolves through a nu ...

  6. POJ 3150 Cellular Automaton(矩阵高速幂)

    题目大意:给定n(1<=n<=500)个数字和一个数字m,这n个数字组成一个环(a0,a1.....an-1).假设对ai进行一次d-step操作,那么ai的值变为与ai的距离小于d的全部 ...

  7. POJ 3150 Cellular Automaton --矩阵快速幂及优化

    题意:给一个环,环上有n块,每块有个值,每一次操作是对每个点,他的值变为原来与他距离不超过d的位置的和,问k(10^7)次操作后每块的值. 解法:一看就要化为矩阵来做,矩阵很好建立,大白书P157页有 ...

  8. LA 3704 Cellular Automaton

    题意概述: 等价地,本题可以转化为下面的问题: 考虑$n \times n$的$0-1$矩阵$A$,在第$i$行上第$[-d+i, d+i]$(模$n$意义下)列对应的元素为$1$,其余为$0$.求$ ...

  9. POJ 3150 Cellular Automaton(矩阵乘法+二分)

    题目链接 题意 : 给出n个数形成环形,一次转化就是将每一个数前后的d个数字的和对m取余,然后作为这个数,问进行k次转化后,数组变成什么. 思路 :下述来自here 首先来看一下Sample里的第一组 ...

随机推荐

  1. docker 建立私有仓库,24.205为镜像仓库所在主机

    一.下载registry #yum install -y python-devel libevent-devel python-pip gcc xz-devel #python-pip install ...

  2. ionic2如何升级到最新版本、配置开发环境

         好久没写东西了,去年用了angular2的RC版本和ionic2写了一个项目,因为开发周期和有些版本不稳定,所以一直没有升级,ng2新版本引用Aot打包,听说优化还不错,现在尝试升级ioni ...

  3. P4433 [COCI2009-2010#1] ALADIN

    题目描述 给你 n 个盒子,有 q 个操作,操作有两种: 第一种操作输入格式为"1 L R A B",表示将编号为L到R的盒子里的石头数量变为(X−L+1)×A mod B,其中 ...

  4. BZOJ4553: [Tjoi2016&Heoi2016]序列 树套树优化DP

    把pos[i]上出现的平常值定义为nor[i]最大值定义为max[i]最小值定义为min[i],那么我们发现在两个值,i(前),j(后),当且仅当max[i]<=nor[j],nor[i]< ...

  5. 在 Linux服务器中安装 Python 3.6

    一.服务器环境配置 在 CentOS 7 中安装 Python 之前,请确保系统中已经有了所有必要的开发依赖: # yum -y groupinstall development # yum -y i ...

  6. 【题解】CF#896 D-Nephren Runs a Cinema

    容易发现这些 vip 用户并没什么用,所以考虑枚举手持50元与100元的人共有多少个.设手持50元的人 \(a\) 个,手持100元的人 \(a - k\) 个,那么一共是 \(2*a - k\) 个 ...

  7. view的阴影效果shadowColor

    btn.layer.shadowColor = UIColor.blackColor().CGColor btn.layer.shadowOffset = CGSizeMake(5, 5) btn.l ...

  8. Linux下cp ~中关于“~”的疑问

    目的:将wi主文件夹下的.bashrc复制到/tmp,并更名为bashrc.对于书上的代码上加“~”存在疑问. cp ~/.bashrc /tmp/bashrc 对命令进行了以下尝试: 为什么不加“~ ...

  9. 【BZOJ4006】【JLOI2015】管道连接

    Description 传送门 Solution 题目要求相同颜色的点必须在一个连通块中,但会有多个颜色同属一个连通块使得解更优的情况. 想一想DP能否行得通:设\(g_i\)表示已考虑颜色状态为\( ...

  10. 【Learning】辛普森积分

    辛普森积分 这种积分法很暴力:只要求你实现出函数求值\(f(x)\). 使用辛普森积分,我们可以求出函数一段区间\([l,r]\)的近似积分.记\(mid=\frac{l+r}2\),有: \[ \i ...