问题描述

忙碌了一个学期的 Q老师 决定奖励自己 N 天假期。

假期中不同的穿衣方式会有不同的快乐值。

已知 Q老师 一共有 M 件衬衫,且如果昨天穿的是衬衫 A,今天穿的是衬衫 B,则 Q老师 今天可以获得 f[A][B] 快乐值。

在 N 天假期结束后,Q老师 最多可以获得多少快乐值?

Input

输入文件包含多组测试样例,每组测试样例格式描述如下:

第一行给出两个整数 N M,分别代表假期长度与 Q老师 的衬衫总数。(2 ≤ N ≤ 100000, 1 ≤ M ≤ 100)

接下来 M 行,每行给出 M 个整数,其中第 i 行的第 j 个整数,表示 f[i][j]。(1 ≤ f[i][j] ≤ 1000000)

测试样例组数不会超过 10。

Output

每组测试样例输出一行,表示 Q老师 可以获得的最大快乐值。

Sample input

3 2
0 1
1 0
4 3
1 2 3
1 2 3
1 2 3

Sample output

2
9

解题思路

由于天数是连续的,明显具有子结构的性质,所以这个题我们可以用DP来做。令f[i][j]表示第 i i i天为止,穿 j j j衣服的快乐值,因此我们可以得到下面的状态转移方程:
f [ i ] [ j ] = m a x ( f [ i − 1 ] [ k ] + H [ k ] [ j ] ) , 1 ≤ k ≤ M (1) f[i][j]=max(f[i-1][k]+H[k][j]), 1\le k\le M \tag{1} f[i][j]=max(f[i−1][k]+H[k][j]),1≤k≤M(1)
其中,k是枚举前一天穿的衣服。经过计算,我们可以发现时间复杂度达到了 O ( 1 0 9 ) O(10^9) O(109),所以必须做到优化,观察这个状态转移方程的形式,联想到矩阵乘法公式:
f [ i ] [ j ] = ∑ k = 1 M ( f 2 [ i ] [ k ] × f 3 [ k ] [ j ] ) (2) f[i][j]=\sum_{k=1}^{M}(f_2[i][k]\times f_3[k][j]) \tag{2} f[i][j]=k=1∑M​(f2​[i][k]×f3​[k][j])(2)
将 f 2 f_2 f2​矩阵中的 f 2 [ i ] [ k ] f_2[i][k] f2​[i][k]看作 f [ i − 1 ] [ k ] f[i-1][k] f[i−1][k],将 f 3 f_3 f3​矩阵中的 f 3 [ k ] [ j ] f_3[k][j] f3​[k][j]看作 H [ k ] [ j ] H[k][j] H[k][j]。我们可以得到:
f [ i ] [ j ] = ∑ k = 1 M ( f [ i − 1 ] [ k ] × H [ k ] [ j ] ) (3) f[i][j]=\sum_{k=1}^{M}(f[i-1][k]\times H[k][j])\tag{3} f[i][j]=k=1∑M​(f[i−1][k]×H[k][j])(3)
观察公式 ( 1 ) (1) (1)与公式 ( 3 ) (3) (3), m a x max max与 ∑ \sum ∑相对应, + + +与 × \times ×相对应。想到或许可以进行矩阵快速幂优化,矩阵快速幂实现的条件是矩阵乘法具有结合律,而公式 ( 1 ) (1) (1)是具有结合律的。证明方法如下:

设A、B、C分别为 a × b , b × c , c × d a\times b, b\times c, c\times d a×b,b×c,c×d的矩阵
( ( A B ) C ) [ i , j ] = max ⁡ l = 1 c ( ( A B ) [ i , l ] + C [ l , j ] ) = max ⁡ l = 1 c ( max ⁡ k = 1 b ( A [ i , k ] + B [ k , l ] ) + C [ l , j ] ) = max ⁡ l = 1 c max ⁡ k = 1 b ( A [ i , k ] + B [ k , l ] + C [ l , j ] ) = max ⁡ k = 1 b max ⁡ l = 1 c ( A [ i , k ] + B [ k , l ] + C [ l , j ] ) = max ⁡ k = 1 b ( A [ i , k ] + max ⁡ l = 1 c ( B [ k , l ] + C [ l , j ] ) ) = max ⁡ k = 1 b ( A [ i , k ] + B C [ k , j ] ) = ( A ( B C ) ) [ i , j ] \begin{aligned} ((AB)C)[i,j] &=\max_{l=1}^{c}((AB)[i,l]+C[l,j])\\ &=\max_{l=1}^{c}(\max_{k=1}^{b}(A[i,k]+B[k,l])+C[l,j])\\ &=\max_{l=1}^{c}\max_{k=1}^{b}(A[i,k]+B[k,l]+C[l,j])\\ &=\max_{k=1}^{b}\max_{l=1}^{c}(A[i,k]+B[k,l]+C[l,j])\\ &=\max_{k=1}^{b}(A[i,k]+\max_{l=1}^{c}(B[k,l]+C[l,j]))\\ &=\max_{k=1}^{b}(A[i,k]+BC[k,j])\\ &=(A(BC))[i,j] \end{aligned} ((AB)C)[i,j]​=l=1maxc​((AB)[i,l]+C[l,j])=l=1maxc​(k=1maxb​(A[i,k]+B[k,l])+C[l,j])=l=1maxc​k=1maxb​(A[i,k]+B[k,l]+C[l,j])=k=1maxb​l=1maxc​(A[i,k]+B[k,l]+C[l,j])=k=1maxb​(A[i,k]+l=1maxc​(B[k,l]+C[l,j]))=k=1maxb​(A[i,k]+BC[k,j])=(A(BC))[i,j]​
因此公式 ( 1 ) (1) (1)可以使用矩阵快速幂来进行优化,矩阵乘法的定义由公式 ( 3 ) (3) (3)更改为公式 ( 1 ) (1) (1)。转移矩阵如下:
a n s [ i ] = [ f [ i ] [ 1 ] ⋮ f [ i ] [ M ] ] = [ H [ 1 ] [ 1 ] ⋯ H [ M ] [ 1 ] ⋮ ⋱ ⋮ H [ 1 ] [ M ] ⋯ H [ M ] [ M ] ] ∗ [ f [ i − 1 ] [ 1 ] ⋮ f [ i − 1 ] [ M ] ] ans[i]=\begin{bmatrix} f[i][1]\\ \vdots\\ f[i][M] \end{bmatrix}= \begin{bmatrix} H[1][1]&\cdots&H[M][1]\\ \vdots&\ddots&\vdots\\ H[1][M]&\cdots&H[M][M] \end{bmatrix}* \begin{bmatrix} f[i-1][1]\\ \vdots\\ f[i-1][M] \end{bmatrix} ans[i]=⎣⎢⎡​f[i][1]⋮f[i][M]​⎦⎥⎤​=⎣⎢⎡​H[1][1]⋮H[1][M]​⋯⋱⋯​H[M][1]⋮H[M][M]​⎦⎥⎤​∗⎣⎢⎡​f[i−1][1]⋮f[i−1][M]​⎦⎥⎤​
初始状态 f [ 1 ] [ 1 ] ∼ f [ 1 ] [ M ] f[1][1]\sim f[1][M] f[1][1]∼f[1][M]均为0,最终结果从 n − 1 n-1 n−1次幂的矩阵中找最大值即可。

需要注意的是,由于矩阵乘法定义改变,不要忘记在矩阵快速幂中的单位矩阵设置为全0矩阵。

完整代码

//#pragma GCC optimize(2)
//#pragma G++ optimize(2)
//#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <climits>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;struct Matrix{Matrix(int _size=0) {Size=_size; mat=new long long*[Size];for (int i=0; i<Size; i++) mat[i]=new long long[Size];for (int i=0; i<Size; i++)for (int j=0; j<Size; j++)mat[i][j]=0;}Matrix(const Matrix& t){Size=t.Size; mat=new long long*[Size];for (int i=0; i<Size; i++) mat[i]=new long long[Size];memcpy(mat,t.mat,sizeof(mat));}~Matrix(){for (int i=0; i<Size; i++) delete[] mat[i];delete[] mat;}Matrix operator*(const Matrix& t) const{//伪.乘法Matrix ret(Size);for (int i=0; i<Size; ++i)for (int j=0; j<Size; ++j)for (int k=0; k<Size; ++k)ret.mat[i][j]=max(ret.mat[i][j],mat[i][k]+t.mat[k][j]);return ret;}Matrix operator%(const int m) const {Matrix ret(Size);for (int i=0; i<Size; i++)for (int j=0; j<Size; j++)ret.mat[i][j]=mat[i][j]%m;return ret;}Matrix& operator=(const Matrix& t){for (int i=0; i<Size; i++) delete[] mat[i];delete[] mat;Size=t.Size;mat=new long long*[Size];for (int i=0; i<Size; i++) mat[i]=new long long[Size];for (int i=0; i<Size; i++)for (int j=0; j<Size; j++)mat[i][j]=t.mat[i][j];return *this;}void quick_pow(int x){Matrix ret(Size);//for (int i=0; i<Size; i++) ret.mat[i][i]=1;//注意,乘法含义改变,单位矩阵全0while(x){if(x&1) {ret=ret*(*this);}*this=(*this)*(*this);x>>=1;}*this=ret;}void output(){printf("Size: %d\n",Size);for (int i=0; i<Size; i++){for (int j=0; j<Size; j++){printf("%lld ",mat[i][j]);}printf("\n");}}int Size;long long** mat;
};
int getint(){int x=0,s=1; char ch=' ';while(ch<'0' || ch>'9'){ ch=getchar(); if(ch=='-') s=-1;}while(ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar();}return x*s;
}
int n,m;
int main(){//ios::sync_with_stdio(false);//cin.tie(0);while(scanf("%d %d",&n,&m)!=EOF){Matrix mat1(m);for (int i=0; i<m; i++)for (int j=0; j<m; j++)scanf("%lld",&mat1.mat[i][j]);mat1.quick_pow(n-1);long long ans=0;for (int i=0; i<m; i++)for (int j=0; j<m; j++)ans=max(ans,mat1.mat[i][j]);//mat1.output();printf("%lld\n",ans);}return 0;
}

Q老师度假(变形矩阵快速幂优化DP)相关推荐

  1. AtCoder abc256全题解(区间合并模板、矩阵快速幂优化dp、线段树……)

    文章目录 A B C-枚举 D-区间合并模板 E-图论建模,函数图的性质 题意 思路 代码 F-树状数组 题意 思路 代码 G-矩阵快速幂优化dp H-线段树 思路 实现 传送门 本文CSDN 本文j ...

  2. 【noip2016十连测round3】T3 涂色游戏 【矩阵快速幂优化dp】

    涂色游戏 题解: 推一推公式. 我们让f[i][j]表示第i列有j种颜色的方案总数,k表示i-1列用了多少种颜色,l表示第i列用了多少种没有在i-1列出现的颜色,G(i,j)表示i个格子涂j种颜色的方 ...

  3. 【POJ - 3744】Scout YYF I(概率dp,矩阵快速幂优化dp)

    题干: 题目大意: 在一条不满地雷的路上(无限长),你现在的起点在1处.在N个点处布有地雷,1<=N<=10.地雷点的可能坐标范围:[1,100000000]. 每次前进p的概率前进一步, ...

  4. 2019.02.11 bzoj4818: [Sdoi2017]序列计数(矩阵快速幂优化dp)

    传送门 题意简述:问有多少长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数,且其中至少有一个数是质数,答案对201704082017040820170408取模(n≤1e9, ...

  5. 2018.11.08 NOIP模拟 景点(倍增+矩阵快速幂优化dp)

    传送门 首先按照题意构造出转移矩阵. 然后可以矩阵快速幂求出答案. 但是直接做是O(n3qlogm)O(n^3qlogm)O(n3qlogm)的会TTT掉. 观察要求的东西发现我们只关系一行的答案. ...

  6. 【BZOJ4861】【BJOI2017】—魔法咒语(AC自动机+矩阵快速幂优化dp)

    传送门 当 l ≤ 100 l\le 100 l≤100时 显然的自动机上 d p dp dp就完了 当 l ≤ 1 e 8 l\le1e8 l≤1e8时直接 d p dp dp显然是不行的 但是发现 ...

  7. czy的后宫——矩阵快速幂优化DP

    题意 有 n 个位置排成一行,可以放 m 种妹子.每个位置可以放也可以不放,规定某些妹子不能相邻,求方案数. 分析 #include<bits/stdc++.h> using namesp ...

  8. 简单计数(构造矩阵 矩阵快速幂优化dp)

    传送门 示例1 输入 1 1 输出 0 分析: 代码: #include <bits/stdc++.h>using namespace std; typedef long long ll; ...

  9. CF989E A Trance of Nightfall(概率+矩阵快速幂优化+倍增)

    CF传送门 洛谷传送门 [题目分析] 在zxy大佬的讲解下终于懂了这道题的做法了qwq... 首先根据题意,出发点不一定在特殊点上,但第一次操作后,之后所有的操作都是在特殊点上,所以先考虑从线上出发的 ...

最新文章

  1. 光纤会在将来完全取代铜缆吗?
  2. SpringBoot快速入门——helloworld(来自官网)
  3. 【机器学习算法专题(蓄力计划)】十二、机器学习中KNN算法
  4. 回腾讯了......
  5. Jquerymobile 简单安装
  6. 微信朋友圈删除后服务器还有吗,删了的朋友圈还可以找回来吗
  7. jQuery1.9+ 废弃的函数和方法 升级Jquery版本遇到的问题
  8. php登录失败后,PhpWind:造成登录失败的主要原因
  9. 5.1 内存模型基础
  10. matlab运行C程序
  11. h5自我介绍作品_自我介绍h5模板
  12. TeamTalk HttpClient详解
  13. 现代管理学 罗珉 第三版
  14. [程序设计]Java实现解析抖音无水印视频
  15. Java开发全终端实战租房项目——项目介绍以及开发后台系统
  16. unity3D用鼠标和射线控制物体移动(一)
  17. 计算机有哪些专业技能,简历计算机技能有哪些
  18. 共阳和共阴数码管详细段码(带图)
  19. 1020 月饼 (25 分)
  20. 【Docker】基于CentOS 8:Docker使用基础

热门文章

  1. 学计算机能不能挣上千万,985名校毕业,年薪不如二本计算机毕业生,学长:千万别选错专业...
  2. 经验总结-RecyclerView列表中获取每个item中已经选择的CheckBox值
  3. linux系统6.8下载,centos6.8
  4. Failed to deserialize payload
  5. 如何查看本机的IP地址?
  6. delphi美团点评劵码核销API(支持验劵、 验劵记录查询、撤销验劵)
  7. AI解锁无人时代 仍需数据安全保驾护航
  8. python的起源简史和优点
  9. 华为简单的生成树协议配置
  10. 灵感个性音源合集 Native Instruments Play Series Kontakt 6