欢迎大家访问我的老师的OJ———caioj.cn

题面描述

传送门

思路

题目可以理解为是一个 n ∗ m n*m n∗m的矩阵,在里面进行一些玄学的操作。

不难发现,操作序列的长度不超过6,那么1~6的最小公倍数是60,

即每经过60秒,所有操作序列都会重新处于最开始的字符处。

那么第 k ( 1 ≤ k ≤ 60 ) k(1\le k\le 60) k(1≤k≤60)秒,第 k + 60 k+60 k+60秒执行的字符与第 k k k秒一定是相同的。

得到了这个结论,我们就可以很容易想到递推,因为这是单调的。

之后发现递推中都是加法。

之后我们就可以运用矩阵乘法来加速运算。

设状态矩阵为 F F F,我们用这样的方法去表示 i i i行 j j j列的石头数:

F [ n u m ( i , j ) ] , n u m ( i , j ) = ( i − 1 ) ∗ m F[num(i,j)],num(i,j)=(i-1)*m F[num(i,j)],num(i,j)=(i−1)∗m

根据题目定义,我们可以得到 F F F的初始状态是 [ 0 0 . . . 0 ] \begin{bmatrix}0&0&...&0\end{bmatrix} [0​0​...​0​]

我们不妨多一个源点 p = n ∗ m + 1 p=n*m+1 p=n∗m+1,使 F [ p ] = 1 F[p]=1 F[p]=1.

因为矩阵乘法,必须要有一个不为 1 1 1的数,才能正常进行操作,否则操作等于无效

那我们也需要一个转移矩阵 A A A来转移状态吧。

对于第 k ( 1 ≤ k ≤ 60 ) k(1\le k\le60) k(1≤k≤60)秒,构造一个转移状态 A k A_k Ak​,行,列下标均为 1 1 1~ n ∗ m + 1 n*m+1 n∗m+1

构造方法类似于跑图:

  1. 若网格 ( i , j ) (i,j) (i,j)第k秒的操作字符为“N”,且 i > 1 i>1 i>1,则令 A k [ n u m ( i , j ) , n u m ( i − 1 , j ) ] = 1 A_k[num(i,j),num(i-1,j)]=1 Ak​[num(i,j),num(i−1,j)]=1,意思就是把石头推到上边的格子。字符"W",“S”,"E"类似。

  2. 若网格 ( i , j (i,j (i,j)第 k k k秒的操作字符时一个数字 x x x,则令 A k [ 0 , n u m ( i , j ) ] = x A_k[0,num(i,j)]=x Ak​[0,num(i,j)]=x。

  3. 令 A k [ p , p ] = 1 A_k[p,p]=1 Ak​[p,p]=1。

  4. A k A_k Ak​的其它部分均赋值为 0 0 0.

上述结构实际上把“状态矩阵”的第 p p p列作为“石头来源”, A k [ p , p ] = 1 A_k[p,p]=1 Ak​[p,p]=1保证 F [ p ] = 1 F[p]=1 F[p]=1

A k [ p , n u m ( i , j ) ] = x A_k[p,num(i,j)]=x Ak​[p,num(i,j)]=x相当于从“石头来源”获取 x x x个石头,放到格子 ( i , j ) (i,j) (i,j)上。

设 A = ∏ i = 1 60 A i , t = q ( 60 + r ( 0 ≤ r &lt; 60 ) A=\prod\limits_{i=1}^{60}A_i,t=q(60+r(0\le r&lt;60) A=i=1∏60​Ai​,t=q(60+r(0≤r<60).根据上面的讨论:
F t = F 0 ∗ A q ∗ ∏ i = 1 r A i F_t=F_0*A^q*\prod\limits_{i=1}^rA_i Ft​=F0​∗Aq∗i=1∏r​Ai​

用矩阵乘法和快速幂计算该式, F t F_t Ft​第 1 1 1~ n ∗ m n*m n∗m列中的最大值即为所求。

另外,对于 A k [ n u m ( i , j ) , n u m ( i − 1 , j ) ] = 1 A_k[num(i,j),num(i-1,j)]=1 Ak​[num(i,j),num(i−1,j)]=1,其实也是另类建边,使石头能够“流过去”。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#define ll long long
#define gc getchar()
using namespace std;
int n,m,t,act,p;
inline int num(int i,int j){return (i-1)*m+j;}
inline void muls(ll a[66][66],ll b[66][66])
{ll w[66][66];memset(w,0,sizeof(w));for(int i=1;i<=p;i++)for(int k=1;k<=p;k++)if(a[i][k])for(int j=1;j<=p;j++)w[i][j]+=a[i][k]*b[k][j];memcpy(a,w,sizeof(w));
}
inline void mul(ll f[66],ll a[66][66])
{ll w[66];memset(w,0,sizeof(w));for(int j=1;j<=p;j++)/*for(int i=1;i<=p;i++)*/for(int k=1;k<=p;k++)/*for(int j=1;j<=p;j++)*/w[j]+=f[k]*a[k][j];/*w[i]=f[j]*a[j][i]*/memcpy(f,w,sizeof(w));
}
char b[20][20],s[100];
ll f[66],e[66][66][66],d[66][66];int a[20][20],c[20][20];
int main()
{scanf("%d%d%d%d",&n,&m,&t,&act);for(int i=1;i<=n;i++){scanf("%s",s+1);for(int j=1;j<=m;j++)a[i][j]=s[j]-'0'+1;}for(int i=1;i<=act;i++)scanf("%s",b[i]);p=n*m+1;for(int k=1;k<=60;k++){for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){int x=a[i][j],y=c[i][j];if(b[x][y]>='0'&&b[x][y]<='9'){e[k][p][num(i,j)]=b[x][y]-'0';e[k][num(i,j)][num(i,j)]=1;}else if(b[x][y]=='N'&&i>1)e[k][num(i,j)][num(i-1,j)]=1;else if(b[x][y]=='S'&&i<n)e[k][num(i,j)][num(i+1,j)]=1;else if(b[x][y]=='W'&&j>1)e[k][num(i,j)][num(i,j-1)]=1;else if(b[x][y]=='E'&&j<m)e[k][num(i,j)][num(i,j+1)]=1;c[i][j]=(y+1)%strlen(b[x]);}e[k][p][p]=1;}memcpy(d,e[1],sizeof(e[1]));for(int k=2;k<=60;k++)muls(d,e[k]);ll ans=0;f[p]=1;int w=t/60;while(w){if(w&1)mul(f,d);muls(d,d);w>>=1;}w=t%60;for(int i=1;i<=w;i++)mul(f,e[i]);for(int i=1;i<p;i++)ans=max(ans,f[i]);printf("%lld\n",ans);return 0;
}

石头游戏[CH3401]相关推荐

  1. Nim 游戏 、⽯头游戏1、石头游戏2

    Nim 游戏 .⽯头游戏1.石头游戏2 文章目录 Nim 游戏 .⽯头游戏1.石头游戏2 **一:Nim 游戏** **二:⽯头游戏** **三.石头游戏2** **方法一:DP 函数** **方法二 ...

  2. 算法作业2-轮流取石头游戏

    两个足够聪明的人玩轮流取石头的游戏,谁取到最后一个石头谁就赢了,他们一次只能取1个.3个.7个或8个石头,写一程序判断n个石头时先取的人是输还是赢. 输入格式: 一个整数n,其值不超过10000000 ...

  3. acwing 206 石头游戏 矩阵快速幂

    题目地址 构建1维数组f(num(i,j)) -> 表示第num(i,j) =((i-1)*m + j)位的石头有多少个.(i,j)表示一个位置 可以知道f的长度为n*m+1.令f[0] = 1 ...

  4. LeetCode:青蛙跳石头游戏

    /* 有n块石头分别在x轴的0,1,...,n-1位置,一致青蛙在石头0,想跳到石头n-1,如果青蛙 在第i块石头上,它最多可以向右跳距离ai,问青蛙能否跳到石头n-1?示例1: Input:a=[2 ...

  5. 2.石头游戏(坑爹)

    题目抽象: 一堆石子两个人轮流取,每次至少要取走一个.先取的人第一次可以取任意多个,但是不能全部取完.之后每个人取石子时,能取的数目最多不能超过对手刚才取的石子数的k倍(k为给定常量).取走最后一个石 ...

  6. 【HNOI2010】【BZOJ2000】stone 取石头游戏

    BZOJ上的Source是骗子QAQ这题根本不是SG函数QAQ Description A 公司正在举办一个智力双人游戏比赛--取石子游戏,游戏的获胜者将会获得 A 公司提 供的丰厚奖金,因此吸引了来 ...

  7. 【bzoj2000】[Hnoi2010]stone 取石头游戏

    Description A 公司正在举办一个智力双人游戏比赛--取石子游戏,游戏的获胜者将会获得 A 公司提 供的丰厚奖金,因此吸引了来自全国各地的许多聪明的选手前来参加比赛. 与经典的取石子游戏相比 ...

  8. 取石头游戏 c语言,[HNOI2010]取石头游戏(博弈论+贪心)

    题目描述: 有\\(n\\)堆石子,每堆石子的个数为\\(a_i\\),保证存在至少一堆石子个数为\\(0\\) 两个人,每个人每次可以取一堆石子,一堆石子可以被取当且仅当它相邻的石子有至少一堆为\\ ...

  9. 移动石头游戏中的博弈问题(洛谷P4136题题解,Java语言描述)

    题目要求 P4136题目链接 分析 一道博弈论的题. 很显然,棋盘大小为 n×nn\times nn×n,左上角已有111枚棋子,那么剩下的可选格子有 n2−1n^2-1n2−1 个. 由题意得,如果 ...

最新文章

  1. 中国电子信息产业发展研究院主办的2018中国软件大会上大快搜索“又双叒叕”获奖了...
  2. 获得插入行身份的最佳方法?
  3. python中的类及self详解_Python类class参数self原理解析
  4. cpu倍频模式怎么调_CPU频率被锁定到800mhz怎么办?
  5. @FeignClient中的@RequestMapping也被SpringMVC加载的问题解决
  6. HashMap keyset()方法
  7. channelinactive触发后不关闭channel_Go语言 | goroutine不只有基础的用法,还有这些你不知道的操作...
  8. LINUX下载及编译libtool
  9. 飞翔(风吹)的flash文字
  10. idea2017永久性破解
  11. SaaS、PaaS、IaaS云服务模式和商业云平台设计与建设方案
  12. linux svc作用,[svc]linux性能监控
  13. Monkey log 分析
  14. Pytorch搭建ResNet网络进行垃圾分类
  15. Faster RER-CNN 论文笔记
  16. excel表格数据导入导出
  17. 使用gcc参数-Wl,–gc-sections,不链接未用函数,减小可执行文件大小
  18. [ 案例源码 ] 利用php开发apicloud 前台加后台源码
  19. 《途客圈创业记:不疯魔,不成活》一一1.1 途我睿的由来
  20. 树莓派新手使用iobroker日志三(米家全家桶加入iobroker)

热门文章

  1. android paint设置字体方向,android paint设置字体 中文字体 楷体 和自动换行方法(zhuan)...
  2. 图像分析、图像理解、图像处理区别
  3. 蓝港公布3D双端动作游戏《黎明之光》 预告片首曝
  4. oracle show parameter,用show parameter也能显示隐含参数
  5. Java数据结构——认识二叉树
  6. macbook通过usb共享网络给iphone上网
  7. TypeScript 中的 export 和 import
  8. \t\t北京 【游玩】水立方 亚洲 最大 室内 嬉水乐园
  9. 少说话多写代码之Python学习066——python程序打包01 编译安装
  10. 蓝桥杯之单片机设计与开发——第八届省赛_基于单片机的电子钟程序设计与调试