[题解][SHOI2013]超级跳马 动态规划/递推式/矩阵快速幂优化
这道题... 让我见识了纪中的强大
这道题是来纪中第二天(7.2)做的,这么晚写题解是因为
我去学矩阵乘法啦啦啦啦啦
对矩阵乘法一窍不通的童鞋戳链接啦
层层递推会TLE,正解矩阵快速幂
首先题意就是给你一个 n 行m 列 的格子图 一只马从棋盘的左上角跳到右下角。每一步它向右跳奇数列,且跳到本行或相邻行。
题意很简单
暴力dp的思路也很简单
但是数据很恶心
虽然远古一点,但毕竟是省选题
1 ≤ n ≤ 50,2 ≤ m ≤ 10^9
不过还是给了我们一点提示:
n这么小?
总之我们先找出转移式
对于每一个点 (i,j) 的
我们可以从它左边所有奇数行跳过来
所以DP[i][i]=sum( 左边间隔偶数列上中下三行的和 )
如果每个点都往前找一次的话
这样复杂度是O(n2m)
得分10
所以我们想到了前缀和
别问我怎么想到的,有什么套路
这种东西真的是灵感
DP[i][j]保存 (i-1)列+(i-3)列......上中下三行的和
这么简化之后,我们的递推式就好写了
时间复杂度O(mn)
甚至可以用滚动数组优化
这样空间也不是问题了O(n)
得分50
DP[i][j] = DP[i-2][j] + DP[i-1][j+1] + DP[i-1][j] + DP[i-1][j-1]
那么怎么得满分呐?
敲黑板划重点啦
观察一下递推式......嗯?递推式啊
那就用矩阵快速幂吧
不过这道题的递推关系有点复杂啊___二维递推
越到这种时候越要冷静观察,感性思考
再吱一声:不会矩阵快速幂的同学戳链接呐
观察一下,递推式需要两行数据
我们把这两行看成两个数据
跟斐波那契数列的递推矩阵一样放在一行
展开来就是像这样的东西(以n=4为例)
再展开
虽然这么看很乱(个P),不过我们只要仔细思考其中的意义就不难明白了
这样写下来之后,我们所需要的 DP[i-2][j] , DP[i-1][j+1] , DP[i-1][j] , DP[i-1][j-1]
就都出现在矩阵L中了
开始填矩阵R
根据矩阵乘法左行右列的规则,每次乘法 矩阵L 的每个元素都有机会被乘到
我们可以在填矩阵的时候自己选择系数(多方便啊)
由于我们的矩阵是 2n 的 , 所以我们需要一个2n*2n的正方形矩阵(我都以4为例呐)
(这是一个已经填好的矩阵)
答案A 的第一行 第一列 等于 矩阵L的第一行 * 矩阵R的第一列(详见矩阵乘法详解)
由于系数都是1,所以我们填1
我还是随便解释一个吧
不然跟其他的题解有什么区别
DP[i][3] = DP[i-2][3] + DP[i-1][2] + DP[i-1][3] + DP[i-1][4]
所以在这个矩阵中,第3列是这么乘的
大家一定都懂了
对吧....
虽然n是不同的,但是矩阵的构造是相似的
所以我写了一个函数来初始化数组L和R
- void _make(int A[LEN][LEN], int B[LEN][LEN], int len) {
- for (int i = ; i <= len; ++i) {
- for (int j = ; j <= len; ++j) {
- if (i == j)
- A[i][j] = A[len + i][j] = A[i][len + j] = ;
- if (i - j == || j - i == )
- A[i][j] = ;
- }
- }
- B[][] = B[][] = B[][len + ] = ;
- }
_make
然后矩阵快速幂就完事了(详细过程见淼淼的矩阵快速幂详解
来了源码
- //
- #include <iostream>
- using namespace std;
- #define LEN 100
- #define MOD 30011
- unsigned int n, m;
- int mat[LEN][LEN] = {}, ans[LEN][LEN];
- void _make(int A[LEN][LEN], int B[LEN][LEN], int len);
- void _mul(int L[LEN][LEN], int R[LEN][LEN], int A[LEN][LEN], int x, int y, int z);
- void _mi(int L[LEN][LEN], int R[LEN][LEN], int A[LEN][LEN], int x, int y, int m);
- int main() {
- freopen("2.in", "r", stdin);
- cin >> n >> m;
- if (m == ) {
- cout << ((n == ) ? () : ());
- return ;
- }
- _make(mat, ans, n);
- _mi(ans, mat, ans, , * n, m - );
- cout << (ans[][n - ] + ans[][n]) % MOD;
- return ;
- }
- void _make(int A[LEN][LEN], int B[LEN][LEN], int len) {
- for (int i = ; i <= len; ++i) {
- for (int j = ; j <= len; ++j) {
- if (i == j)
- A[i][j] = A[len + i][j] = A[i][len + j] = ;
- if (i - j == || j - i == )
- A[i][j] = ;
- }
- }
- B[][] = B[][] = B[][len + ] = ;
- }
- void _mul(int L[LEN][LEN], int R[LEN][LEN], int A[LEN][LEN], int x, int y, int z) {
- long long cmp[LEN][LEN] = {};
- for (int i = ; i <= x; ++i)
- for (int j = ; j <= z; j++)
- for (int k = ; k <= y; k++)
- cmp[i][j] = (cmp[i][j] + L[i][k] * R[k][j]) % MOD;
- for (int i = ; i <= x; ++i)
- for (int j = ; j <= z; ++j)
- A[i][j] = cmp[i][j];
- }
- void _mi(int L[LEN][LEN], int R[LEN][LEN], int A[LEN][LEN], int x, int y, int m) {
- int cmp[LEN][LEN];
- for (int i = ; i <= x; ++i)
- for (int j = ; j <= y; ++j)
- cmp[i][j] = L[i][j];
- while (m > ) {
- if (m & )
- _mul(cmp, R, cmp, x, y, y);
- m >>= ;
- _mul(R, R, R, y, y, y);
- }
- for (int i = ; i <= x; ++i)
- for (int j = ; j <= y; ++j)
- A[i][j] = cmp[i][j];
- }
超级跳马
[题解][SHOI2013]超级跳马 动态规划/递推式/矩阵快速幂优化的更多相关文章
- HDU - 2604 Queuing(递推式+矩阵快速幂)
Queuing Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Su ...
- HDU5950 Recursive sequence 非线性递推式 矩阵快速幂
题目传送门 题目描述:给出一个数列的第一项和第二项,计算第n项. 递推式是 f(n)=f(n-1)+2*f(n-2)+n^4. 由于n很大,所以肯定是矩阵快速幂的题目,但是矩阵快速幂只能解决线性的问题 ...
- hdu 5950 Recursive sequence 递推式 矩阵快速幂
题目链接 题意 给定\(c_0,c_1,求c_n(c_0,c_1,n\lt 2^{31})\),递推公式为 \[c_i=c_{i-1}+2c_{i-2}+i^4\] 思路 参考 将递推式改写\[\be ...
- HDU-6185-Covering(推递推式+矩阵快速幂)
Covering Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Su ...
- [HDOJ2604]Queuing(递推,矩阵快速幂)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2604 递推式是百度的,主要是练习一下如何使用矩阵快速幂优化. 递推式:f(n)=f(n-1)+f(n- ...
- [Lonlife1031]Bob and Alice are eating food(递推,矩阵快速幂)
题目链接:http://www.ifrog.cc/acm/problem/1031 题意:6个水果中挑出n个,使得其中2个水果个数必须是偶数,问有多少种选择方法. 设中0代表偶数,1代表奇数.分别代表 ...
- 【图灵杯 F】一道简单的递推题(矩阵快速幂,乘法模板)
Description 存在如下递推式: F(n+1)=A1*F(n)+A2*F(n-1)+-+An*F(1) F(n+2)=A1*F(n+1)+A2*F(n)+-+An*F(2) - 求第K项的值对 ...
- hihoCoder 1143 : 骨牌覆盖问题·一(递推,矩阵快速幂)
[题目链接]:click here~~ 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 骨牌,一种古老的玩具.今天我们要研究的是骨牌的覆盖问题: 我们有一个2xN的长条形 ...
- UESTC - 1610 递推方程+矩阵快速幂
感觉像是HDU Keyboard的加强版,先推出3张牌时的所有组合,然后递推出n张牌 看到n=1e18时吓尿了 最后24那里还是推错了.. (5行1列 dp[1][n],dp[2][n],dp[3][ ...
随机推荐
- Editplus注册码生成代码
function generate_editplus_regcode(username) { var list = [0,49345,49537,320,49921,960,640,49729,506 ...
- maven项目创建3 (依赖版本冲突)
调节原则 1 路径近者优先原则 自己添加一个想要依赖的版本 2第一声明者优先原则 谁排在前面就用谁的 以上两种统称为 调节原则 排除原则 排除自己的不想要的版本 版本锁定 谁能够提供锁定的版本,就用谁 ...
- Java并发编程的艺术笔记(四)——ThreadLocal的使用
ThreadLocal,即线程变量,是一个以ThreadLocal对象为键.任意对象为值的存储结构.这个结构被附带在线程上,也就是说一个线程可以根据一个ThreadLocal对象查询到绑定在这个线程上 ...
- GC详解
GC,即就是Java垃圾回收机制.目前主流的JVM(HotSpot)采用的是分代收集算法.与C++不同的是,Java采用的是类似于树形结构的可达性分析法来判断对象是否还存在引用.即:从gcroot开始 ...
- C++入门经典-例6.6-字符串复制
1:字符串复制函数strcpy的格式如下: strcpy(字符数组名,字符串) 其作用是把字符串中的字符串复制到字符数组中.需要注意的是,字符串结束标志'\0'也一同被复制. 注意是将后面的内容复制给 ...
- Struts初学
自我概述 今天看了Struts,感觉这是个非常好用的东西!虽然它已经过时了,被springMVC取代了,但是仍然有了解的价值. 可是在学习过程中遇到了很多问题,比如其中一些原理很是抽象,有一些问题莫名 ...
- TreeMap元素必须实现Comparable接口
纠正一下,TreeMap实现一定顺序是通过Comparable接口的,而他实现元素不重复也是完全通过compareTo,而不是hashCode和equals,因为debug不会走到hashCode和e ...
- python dict字典添加元素
已存在的字典进行赋值操作 可为该字典添加新元素例子:a = {‘age’: 23, ‘name’: ‘lala}a[school] = ‘nanhaizhongxue’print a>>& ...
- What exactly is the parameter e (event) and why pass it to JavaScript functions?
What exactly is the parameter e (event) and why pass it to JavaScript functions? 问题 Well, when I lea ...
- Moodle LMS 开源教育系统
http://docs.websoft9.com/xdocs/moodle-image-guide/ 帮助文档 示例图:没有细研究