CH 3401 - 石头游戏 - [矩阵快速幂加速递推]
题目链接:传送门
描述
石头游戏在一个 $n$ 行 $m$ 列 ($1 \le n,m \le 8$) 的网格上进行,每个格子对应一种操作序列,操作序列至多有 $10$ 种,分别用 $0 \sim 9$ 这 $10$ 个数字指明。
操作序列是一个长度不超过 $6$ 且循环执行、每秒执行一个字符的字符串。每秒钟,所有格子同时执行各自操作序列里的下一个字符。序列中的每个字符是以下格式之一:
数字 $0 \sim 9$:表示拿 $0 \sim 9$ 个石头到该格子。
$NWSE$:表示把这个格子内所有的石头推到相邻的格子,$N$ 表示上方,$W$ 表示左方,$S$ 表示下方,$E$ 表示右方。
$D$:表示拿走这个格子的所有石头。
给定每种操作序列对应的字符串,以及网格中每个格子对应的操作序列,求石头游戏进行了 t 秒之后,石头最多的格子里有多少个石头。在游戏开始时,网格是空的。
输入格式
第一行4个整数 $n, m, t, act$。
接下来 $n$ 行,每行 $m$ 个字符,表示每个格子对应的操作序列。
最后 $act$ 行,每行一个字符串,表示从 $0$ 开始的每个操作序列。
输出格式
一个整数:游戏进行了 $t$ 秒之后,所有方格中最多的格子有多少个石头。
样例输入
1 6 10 3
011112
1E
E
0
样例输出
3
样例解释
这是另一个类似于传送带的结构。左边的设备0间隔地产生石头并向东传送。设备1向右传送,直到设备2。10秒后,总共产生了5个石头,2个在传送带上,3个在最右边。
题解:
(以下参考李煜东《算法竞赛进阶指南》)
一般来说,若一类问题具有以下特点:
- 可以抽象出一个长度为 $n$ 的一维向量(称作状态矩阵),该向量在每个单位时间发生一次变化。
- 变化的形式是一个线性递推:将状态矩阵乘上一个转移矩阵,即可得下一秒时的状态矩阵。
- 该递推式在每个时间可能作用于不同的数据,但本身始终不变。
- 向量变化时间很长,即递推的轮次很多,但是向量本身长度不长。
那么,可以考虑使用矩阵快速幂加速递推。
回到本题:
由于状态矩阵需要是一维向量的缘故,不妨把网格重组为一维向量,这很简单,原来网格的第 $i$ 行第 $j$ 列变为现在的第 $pos(i,j) = (i-1)*m + j$ 列。
即设 $F_{k}[pos(i,j)]$ 代表第 $k$ 秒时,网格第 $i$ 行第 $j$ 列中的石头数目。
考虑到本题中存在一个可以无限取石头的“石头源”,因此不妨对状态矩阵再添加第 $0$ 列,对任意时刻 $k$ 始终有 $F_{k}[0] = 1$,作为“石头源”。
初始化状态矩阵 $F_{k} = [1, 0, 0, \cdots, 0]$。
注意到操作序列长度不超过 $6$,$1 \sim 6$ 的最小公倍数为 $60$,也就是说,不妨把全部操作序列都补成长度为 $60$ 的操作序列,这样一来所有操作的循环节固定为 $60$。
不妨统计出第 $k(1 \le k \le 60)$ 秒各个格子都执行什么操作,假设全部操作可由方阵 $A_k$ 表示,则求 $A_k$ 的方法如下:
- 若某个网格 $(i,j)$ 在第 $k$ 秒执行 $N$ 操作,那么不难知道 $A_k[pos(i,j),pos(i-1,j)]$ 是决定了网格 $(i,j)$ 对下一秒网格 $(i-1,j)$ 贡献的系数,因此令 $A_k[pos(i,j),pos(i-1,j)] = 1$。其他平推操作同理。
- 若某个网格 $(i,j)$ 在第 $k$ 秒执行取 $x$ 个石头的操作,首先,原本格子上有的石头要保留,因此 $A_k[pos(i,j),pos(i,j)] = 1$(这个好像书上没有讲到);其次,从“石头源” $F_{k}[0]$ 拿取石头,乘上 $A_k[0,pos(i,j)] = x$ 倍,放入网格 $(i,j)$ 即可。
- 始终令 $A_k[0,0] = 1$,即“石头源”始终保持不变。
- 若两个网格 $(i_1,j_1)$ 和 $(i_2,j_2)$ 之间没有联系,则 $A_k[pos(i_1,j_1),pos(i_2,j_2)] = 0$。若网格 $(i,j)$ 扔掉本格全部石头,则 $A_k[pos(i,j),pos(i,j)] = 0$。
使用矩阵快速幂加速递推时,遇到常数项,可以在状态矩阵中增加一列常数列,始终存储 $1$,它乘上适当的系数后,可以为状态矩阵的其他任何列提供任何常数。
在算出了 $A_1 \sim A_{60}$ 之后,我们就可以分割 $t = q \times 60 + r(0 \le r < 60)$,就可以有 $F_t = F_0 \times (A_1 \times \cdots \times A_{60})^q \times (A_1 \times \cdots \times A_r)$。
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+;
typedef long long ll; const int DIM=;
int dim;
struct Matrix
{
ll mat[DIM][DIM];
Matrix operator*(Matrix const &oth)const
{
Matrix res;
memset(res.mat,,sizeof(res.mat));
for(int i=;i<dim;i++)
for(int j=;j<dim;j++)
for(int k=;k<dim;k++)
res.mat[i][j]+=mat[i][k]*oth.mat[k][j];
return res;
}
}A,a[],F0,Ft;
Matrix fpow(Matrix base,ll n)
{
Matrix res;
memset(res.mat,,sizeof(res.mat));
for(int i=;i<dim;i++) res.mat[i][i]=;
while(n)
{
if(n&) res=res*base;
base=base*base;
n>>=;
}
return res;
} int n,m,t,q;
int type[][];
char op[][];
inline int pos(int i,int j){return (i-)*m+j;}
int main()
{
scanf("%d%d%d%d",&n,&m,&t,&q);
dim=n*m+;
for(int i=;i<=n;i++)
{
char tmp[];
scanf("%s",tmp+);
for(int j=;j<=m;j++) type[i][j]=tmp[j]-'';
} for(int i=;i<q;i++)
{
scanf("%s",op[i]);
int len=strlen(op[i]);
for(int k=len;k<;k++) op[i][k]=op[i][k%len];
op[i][]='\0';
} memset(A.mat,,sizeof(A.mat));
for(int i=;i<=n*m;i++) A.mat[i][i]=; for(int k=;k<=;k++)
{
memset(a[k].mat,,sizeof(a[k].mat)); a[k].mat[][]=;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
{
int t=type[i][j];
char o=op[t][k-]; if(''<=o && o<='') {
a[k].mat[pos(i,j)][pos(i,j)]=;
a[k].mat[][pos(i,j)]=o-'';
continue;
}
if(o=='N' && i>) {
a[k].mat[pos(i,j)][pos(i-,j)]=;
continue;
}
if(o=='S' && i<n) {
a[k].mat[pos(i,j)][pos(i+,j)]=;
continue;
}
if(o=='W' && j>) {
a[k].mat[pos(i,j)][pos(i,j-)]=;
continue;
}
if(o=='E' && j<m) {
a[k].mat[pos(i,j)][pos(i,j+)]=;
continue;
}
}
A=A*a[k];
} memset(F0.mat,,sizeof(F0.mat));
F0.mat[][]=; if(t/>) Ft=F0*fpow(A,t/);
else Ft=F0;
for(int i=;i<=t%;i++) Ft=Ft*a[i]; ll mx=;
for(int j=;j<=n*m;j++) mx=max(mx,Ft.mat[][j]);
printf("%lld\n",mx);
}
CH 3401 - 石头游戏 - [矩阵快速幂加速递推]的更多相关文章
- HDU 5950 - Recursive sequence - [矩阵快速幂加速递推][2016ACM/ICPC亚洲区沈阳站 Problem C]
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5950 Farmer John likes to play mathematics games with ...
- HDU 1757 矩阵快速幂加速递推
题意: 已知: 当x<10时:f(x)=x 否则:f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + --+ a9 * f(x-10); 求:f(x ...
- CH3401 石头游戏(矩阵快速幂加速递推)
题目链接:传送门 题目: 石头游戏 0x30「数学知识」例题 描述 石头游戏在一个 n 行 m 列 (≤n,m≤) 的网格上进行,每个格子对应一种操作序列,操作序列至多有10种,分别用0~9这10个数 ...
- 洛谷P1357 花园(状态压缩 + 矩阵快速幂加速递推)
题目链接:传送门 题目: 题目描述 小L有一座环形花园,沿花园的顺时针方向,他把各个花圃编号为1~N(<=N<=^).他的环形花园每天都会换一个新花样,但他的花园都不外乎一个规则,任意相邻 ...
- [bzoj1008](HNOI2008)越狱(矩阵快速幂加速递推)
Description 监狱有连续编号为1...N的N个房间,每个房间关押一个犯人,有M种宗教,每个犯人可能信仰其中一种.如果相邻房间的犯人的宗教相同,就可能发生越狱,求有多少种状态可能发生越狱 In ...
- HDU5950 Recursive sequence (矩阵快速幂加速递推) (2016ACM/ICPC亚洲赛区沈阳站 Problem C)
题目链接:传送门 题目: Recursive sequence Time Limit: / MS (Java/Others) Memory Limit: / K (Java/Others) Total ...
- [bzoj1009](HNOI2008)GT考试 (kmp+矩阵快速幂加速递推)
Description 阿 申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字.他的不吉利数学 A1A2...Am(0&l ...
- POJ3070 Fibonacci(矩阵快速幂加速递推)【模板题】
题目链接:传送门 题目大意: 求斐波那契数列第n项F(n). (F(0) = 0, F(1) = 1, 0 ≤ n ≤ 109) 思路: 用矩阵乘法加速递推. 算法竞赛进阶指南的模板: #includ ...
- 2019.2.25考试T1, 矩阵快速幂加速递推+单位根反演(容斥)
\(\color{#0066ff}{题解}\) 然后a,b,c通过矩阵加速即可 为什么1出现偶数次3没出现的贡献是上面画绿线的部分呢? 考虑暴力统计这部分贡献,答案为\(\begin{aligned} ...
随机推荐
- ios实例开发精品源码文章推荐(8.28)
iOS源码:游戏引擎-推箱子游戏 <ignore_js_op> http://www.apkbus.com/android-106392-1-11.html iOS源码:进度条-Color ...
- .Net可扩展的单据编号生成器-SNF.CodeRule--SNF快速开发平台3.2
1.背景 在企业应用中单据编号的自定义是一个很常见的需求,如工号.业务单据编码等,能不能抽象一个通用的框架呢? 2.思路 这里的难点在于实现"解释器",比如将"前缀&qu ...
- netty实现多个handler顺序调用
在netty中,一次数据交互,可以由多个handler去处理,例如 handler1 和 handler2,那么,在前面那个handler的 messageReceived 的最后要加上 ctx.se ...
- Atitit 列出wifi热点以及连接
Atitit 列出wifi热点以及连接 配置命令 >netsh wlan /?1 显示已经有的配置netsh wlan show profiles1 C:\Users\Administrato ...
- linux每日命令(22):find命令参数详解
一. name选项 文件名选项是find命令最常用的选项,要么单独使用该选项,要么和其他选项一起使用. 可以使用某种文件名模式来匹配文件,记住要用引号将文件名模式引起来. 不管当前路径是什么,如果想要 ...
- MyBean通用报表插件介绍
特性: 1.基于MyBean插件平台.可以在任何插件中无缝调用显示. 2.其他窗体中无需引用报表控件.就可以拥有报表的设计预览打印等功能. 3.甚至可以不用带包,制作报表插件,也就是说你可以将RM的报 ...
- ref和引用类型传参的区别
引用类型对象本身不改变,只改变对象的属性时,我们在操作同一个对象:(类似c++指针指向的地址) 如果连对象本身都可能会改变,又要保证在操作同一个对象,就用ref传引用类型的对象吧!(类似c++指向一个 ...
- Java知多少(2)虚拟机(JVM)以及跨平台原理
相信大家已经了解到Java具有跨平台的特性,可以“一次编译,到处运行”,在Windows下编写的程序,无需任何修改就可以在Linux下运行,这是C和C++很难做到的. 那么,跨平台是怎样实现的呢?这就 ...
- Docker孵化的5个开源项目
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/M2l0ZgSsVc7r69eFdTj/article/details/81977243 回想过去短短 ...
- Kubernetes集群部署之二CA证书制作
创建TLS证书和秘钥 kubernetes 系统的各组件需要使用 TLS 证书对通信进行加密,本文档使用 CloudFlare 的 PKI 工具集 cfssl 来生成 Certificate Auth ...