题目描述

现有一个n 行m 列的棋盘,一只马欲从棋盘的左上角跳到右下角。每一步它向右跳奇数列,且跳到本行或相邻行。跳越期间,马不能离开棋盘。试求跳法种数mod 30011。

输入输出格式

输入格式:

仅有一行,包含两个正整数n, m,表示棋盘的规模。

输出格式:

仅有一行,包含一个整数,即跳法种数mod 30011。

输入输出样例

输入样例#1:

3 5

输出样例#1:

10

说明

对于10%的数据,1 ≤ n ≤ 10,2 ≤ m ≤ 10;

对于50%的数据,1 ≤ n ≤ 10,2 ≤ m ≤ 10^5;

对于80%的数据,1 ≤ n ≤ 10,2 ≤ m ≤ 10^9;

对于100%的数据,1 ≤ n ≤ 50,2 ≤ m ≤ 10^9。


题解

好久没写矩乘有点忘了

但是这种不难的题还是可以写出来的==

DP式子显然\(f[i][j] = (Sum[i-1][j]+Sum[i-1][j-1]+Sum[i-1][j+1])\)

那个\(Sum[i][j]\)表示的是第j行前i列的前缀和

然后这样不好做矩乘

可以用\(f[i][j]\)表示第j行前i列的前缀和

然后就是\(f[i][j] = f[i-2][j] + f[i-1][j] + f[i-1][j-1] + f[i-1][j+1]\)

但是这是个前缀和

所以\(Ans=f[m-1][n]+f[m-1][n-1]\)

这样就可以矩乘了

构造一个\((1 , n*2)\)的初始矩阵

前n个表示的是当前列的每一行的\(f[][]\)

后n个表示的是当前列的上一列的每一行的\(f[][]\)

然后转移矩阵就肥肠简单了

只需要把要转移的位置补上1就可以了

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int N = 105 ;
const int mod = 30011 ;
using namespace std ;
int n , m , E ;
int t[N][N] , Ans ;
struct Matrix {
int f[N][N] ;
inline Matrix () { memset(f , 0 , sizeof(f)) ; }
inline void Start() { for(int i = 1 ; i <= E ; i ++) f[i][i] = 1 ; }
inline friend Matrix operator * (Matrix a , Matrix b) {
Matrix temp ;
for(int i = 1 ; i <= E ; i ++)
for(int j = 1 ; j <= E ; j ++)
for(int k = 1 ; k <= E ; k ++)
temp.f[i][j] = (temp.f[i][j] + a.f[i][k] * b.f[k][j]) % mod ;
return temp ;
}
} st , b , Now ; inline Matrix Fpw(Matrix Base , int k) {
Matrix temp ; temp.Start() ;
while(k) {
if(k & 1) temp = temp * Base ;
Base = Base * Base ; k >>= 1 ;
}
return temp ;
}
int main() {
cin >> n >> m ; t[1][1] = 1 ; E = (n << 1) ;
for(int i = 1 ; i <= n ; i ++) t[2][i] = (t[1][i] + t[1][i - 1] + t[1][i + 1]) % mod ;
if(m <= 3) { Ans = (t[m - 1][n] + t[m - 1][n - 1]) % mod ; printf("%d\n",Ans) ; return 0 ; }
for(int i = 1 ; i <= n ; i ++) st.f[1][i] = t[2][i] ;
for(int i = n + 1 ; i <= E ; i ++) st.f[1][i] = t[1][i - n] ;
for(int i = 1 ; i <= n ; i ++) {
b.f[i][i] = 1 ;
if(i != 1) b.f[i - 1][i] = 1 ;
if(i != n) b.f[i + 1][i] = 1 ;
b.f[i + n][i] = 1 ;
}
for(int i = n + 1 ; i <= E ; i ++) b.f[i - n][i] = 1 ;
Now = Fpw(b , m - 3) ; st = st * Now ;
Ans = (st.f[1][n] + st.f[1][n - 1]) % mod ;
cout << Ans << endl ;
return 0 ;
}

[SHOI2013]超级跳马的更多相关文章

  1. [BZOJ 4417][Shoi2013]超级跳马

    4417: [Shoi2013]超级跳马 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 379  Solved: 230[Submit][Status ...

  2. 洛谷 P3990 [SHOI2013]超级跳马 解题报告

    P3990 [SHOI2013]超级跳马 题目描述 现有一个\(n\) 行 \(m\) 列的棋盘,一只马欲从棋盘的左上角跳到右下角.每一步它向右跳奇数列,且跳到本行或相邻行.跳越期间,马不能离开棋盘. ...

  3. [题解][SHOI2013]超级跳马 动态规划/递推式/矩阵快速幂优化

    这道题... 让我见识了纪中的强大 这道题是来纪中第二天(7.2)做的,这么晚写题解是因为 我去学矩阵乘法啦啦啦啦啦对矩阵乘法一窍不通的童鞋戳链接啦 层层递推会TLE,正解矩阵快速幂 首先题意就是给你 ...

  4. BZOJ4417: [Shoi2013]超级跳马

    Description 现有一个n行m列的棋盘,一只马欲从棋盘的左上角跳到右下角.每一步它向右跳奇数列,且跳到本行或相邻行.跳越期间,马不能离开棋盘.例如,当n = 3, m = 10时,下图是一种可 ...

  5. 【BZOJ4417】: [Shoi2013]超级跳马

    题目链接: 传送. 题解: 矩阵快速幂优化DP. 先考虑$nm^2$DP,设$f_{(i,j)}$表示从$1,1$到$i,j$的方案,显然这个方程和奇偶性有关,我们考虑某列的$i$同奇偶性的转移和奇偶 ...

  6. Luogu P3990 [SHOI2013]超级跳马

    这道题还是一道比较不可做的矩阵题 首先我们先YY一个递推的算法:令f[i][j]表示走到第i行第j列时的方案数,那么有以下转移: f[i][j]=f[i-1][j-2*k+1]+f[i+1][j-2* ...

  7. 【bzoj4417】[Shoi2013]超级跳马 矩阵乘法

    题目描述 现有一个n行m列的棋盘,一只马欲从棋盘的左上角跳到右下角.每一步它向右跳奇数列,且跳到本行或相邻行.跳越期间,马不能离开棋盘.例如,当n = 3, m = 10时,下图是一种可行的跳法.   ...

  8. P3990 [SHOI2013]超级跳马

    传送门 首先不难设\(f[i][j]\)表示跳到\((i,j)\)的方案数,那么不难得到如下转移 \[f[i][j]=\sum\limits_{k=1}^{\frac n2}f[i-2k+1][j-1 ...

  9. BZOJ 4417 Luogu P3990 [SHOI2013]超级跳马 (DP、矩阵乘法)

    题目链接: (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=4417 (luogu)https://www.luogu.org/prob ...

随机推荐

  1. cdq分治入门--BZOJ1176: [Balkan2007]Mokia

    对w*w,w<=2000000的矩形,一开始全是0(或一开始全是s),n<=170000个操作,每次操作:矩阵内某点加上一个数,查某一个子矩阵的和,保证修改数<=160000,询问数 ...

  2. 创建Django项目(六)——模板

    2013-08-07 22:42:30|           1.设置模板路径         打开 settings.py 文件,修改 TEMPLATE_DIRS 内容,指向模板存放的绝对路径,而不 ...

  3. CDOJ1339 郭大侠与线上游戏(维护一个set中的中位数——平衡树/双set)

    http://acm.uestc.edu.cn/#/problem/show/1339 题意:有三种操作,分别是. 1.向队列推入一个数x. 2.弹出这个队列的第一个数字 3.查询这个队列的中位数是多 ...

  4. <项目><day11>查看用户浏览过的商品

    <项目>查看用户浏览过的商品 1.创建一个entity包储存实体对象 1.1创建一个Product的类存储实体对象 对象具有以下属性,并添加set和get方法,含参和不含参的构造方法,to ...

  5. LOAP& its implimenlation

    LDAP 概念 LDAP的英文全称是Lightweight Directory Access Protocol,简称为LDAP,LDAP是轻量目录访问协议,LDAP是轻量目录访问协议.简单的说来,LD ...

  6. Java File类 mkdir 不能创建多层目录,如果是多层,可以调mkdirs

    public static void createDir(String destDirName) { File dir = new File(destDirName); if (!dir.exists ...

  7. muduo定时器、多线程模型及epoll的封装

    timerfd是Linux为用户程序提供的一个定时器接口,这个接口基于文件描述符. clock_gettime函数可以获取系统时钟,精确到纳秒.需要在编译时指定库:-lrt.可以获取两种类型时间: C ...

  8. FTP指令说明

    安装vsftpd: listen=YES: 是否监听端口 anonymous_enable=NO: 是否启用匿名用户 local_enable=YES: 是否允许本地用户登录 write_enable ...

  9. datatables对于某一特定的列进行自定义排序

    首先说下里边的api,其中第一个是order,这个里边是设置哪些排序哪些不排序的,比如:$('#example').dataTable( {     "order": (funct ...

  10. i18n国际化的例子

    这个可以点击菜单进行中英文切换,每次切换就可以改变sessionStorage.languge,进行改变i18n的参数lang的值,然后重新调用下就可以了. 工程结构: i18n--| |---css ...