[矩阵乘法][DP]Vijos1067 Warcraft III 守望者的烦恼

题目梗概

n个单位的路程,主角每次最多可以走k个单位(也就是每次可以走1-k个单位),问最后到第n个监狱的方法数。

思考

DP转移方程并不难推导:

dp[i]表示第i个监狱的方法数

$dp\left [ i \right ] = dp\left [ i-1 \right ] + dp\left [ i-2 \right ]\cdots \cdots + dp\left [ i-k-1 \right ]$

但是这个n有点太大了,所以我们需要对DP方程进行优化。

仔细观察转移方程会发现,每次都是加上 上一个,减去上一个的末尾。 所以这种形式我们就可以用矩阵来进行优化了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int N = 25;
const int MOD = 7777777;
typedef long long LL;
int t,m,n,k;
struct Mat
{
LL s[12][12];
}a,b;
Mat multiply(Mat x, Mat y)
{
    Mat c;
    memset(c.s,0,sizeof(c.s));
    for(int i = 0;i < k; ++i)
        {
            for(int j = 0;j < k; ++j)
            {
                for(int z = 0; z < k; ++z)
                {
                    c.s[i][j] += x.s[i][z] * y.s[z][j];
                    c.s[i][j] %= MOD;
                }
            }
        }
    return c;
}
void init()
{
    memset(a.s,0,sizeof(a.s));
    memset(b.s,0,sizeof(b.s));
        //这里看不懂的看我下面的图片
    a.s[0][0] = 1;
    for(int i = 1; i < k; ++i)
    {
        a.s[i][i-1] = 1;
        a.s[0][i] = 1;
    }
    for(int i = 0; i < k;i++)
    b.s[i][0] = 1;
}
LL calc(){
    while(n)//矩阵快速幂
    {
        if(n & 1)
        b = multiply(b,a);
        a = multiply(a,a);
        n >>= 1;
    }
    return b.s[0][0];
}
int main()
{
    while(~scanf("%d%d",&k,&n))
    {
    init();
    LL ans = calc();
    printf("%lld\n",ans);
    }
}

首先看我这个Tex,我们假定k是2,建立一个2*2的矩阵,就拿样例说吧。

n=1 

n=2 

n=3 

n=4 

这个2*2的矩阵是辅助作用,它有什么作用呢?首先按照矩阵乘法,产生的新矩阵的第一行储存的是当前dp[i]的值,第二行储存的是是dp[i-1]的值,用矩阵相乘的形式,来计算DP方程。但是时间复杂度O(n),那还不是等于没优化吗?

这时候我们就可以使用矩阵快速幂(时间复杂度${log_{2}}^{n}$),矩阵快速幂不懂的去百度教程。

再简述一下为什么矩阵快速幂是可行的:

因为矩阵乘法具有结合律 A*B*C=A*C*B

所以$A\times B^{n} = A\times B^{n-2}\times B^{2}=A \times B^{2} \times B^{n-2}$

时间: 2024-10-25 07:20:29

[矩阵乘法][DP]Vijos1067 Warcraft III 守望者的烦恼的相关文章

[Vijos1067]Warcraft III 守望者的烦恼(DP + 矩阵优化)

传送门 可知 f[i] = f[i - 1] + f[i - 2] + ... + f[i - k] 直接矩阵优化就好了 #include <cstdio> #include <cstring> #define p 7777777 #define LL long long int n, k; struct Matrix { int n, m; LL a[11][11]; Matrix() { n = m = 0; memset(a, 0, sizeof(a)); } }; inli

VOJ 1067 Warcraft III 守望者的烦恼 (矩阵快速幂+dp)

题目链接 显然可知 dp[n] = dp[n-k] + dp[n-k+1] + ... +dp[n-1]; 然后要用矩阵来优化后面的状态转移. 也就是矩阵 0 1 0 0    a     b 0 0 1 0 * b =  c 0 0 0 1    c     d 1 1 1 1    d    a+b+c+d 然后跑快速幂 #include <iostream> #include <cstdio> #include <algorithm> #include <c

矩阵经典题目七:Warcraft III 守望者的烦恼(矩阵加速递推)

https://www.vijos.org/p/1067 很容易推出递推式f[n] = f[n-1]+f[n-2]+......+f[n-k]. 构造矩阵的方法:构造一个k*k的矩阵,其中右上角的(k-1)*(k-1)的矩阵是单位矩阵,第k行的每个数分别对应f[n-1],f[n-2],,f[n-k]的系数.然后构造一个k*1的矩阵,它的第i行代表f[i],是经过直接递推得到的.设ans[][]是第一个矩阵的n-k次幂乘上第二个矩阵,f[n]就是ans[k][1]. 注意:用__int64 #in

矩阵十题【七】vijos 1067 Warcraft III 守望者的烦恼

题目链接:https://vijos.org/p/1067 题目大意:给你一个k以及n,k代表最多走的步数,n代表一共要走的步数. 问一共有多少种方法,结果mod7777777 题目意思是很明了,具体的公式也能推出来 状态转移方程为:f[n]=f[n-1]+f[n-2]+....f[n-k]. f[0]=1 当k=1,   f[1]=1; f[2]=f[1]=1; f[3]=f[2]=1; f[4]=f[3]=1; 当k=2,   f[1]=1; f[2]=f[1]+f[0]=2; f[3]=f

VOJ 1067 Warcraft III 守望者的烦恼 (矩阵高速功率+dp)

主题链接 明显的 dp[n] = dp[n-k] + dp[n-k+1] + ... +dp[n-1]; 然后要用矩阵来优化后面的状态转移. 也就是矩阵 0 1 0 0    a     b 0 0 1 0 * b =  c 0 0 0 1    c     d 1 1 1 1    d    a+b+c+d 然后跑高速幂 #include <iostream> #include <cstdio> #include <algorithm> #include <cm

Warcraft III 守望者的烦恼

题目链接: 这道题跟斐波那契数列类似,快速幂矩阵随便推一推就出来了! #pragma GCC optimize("O3") #include <bits/stdc++.h> using namespace std; #define ll long long #define re register #define pb push_back #define fi first #define se second const int N=1e6+10; const int mod=

【BZOJ4870】组合数问题 [矩阵乘法][DP]

组合数问题 Time Limit: 10 Sec  Memory Limit: 512 MB[Submit][Status][Discuss] Description Input 第一行有四个整数 n, p, k, r,所有整数含义见问题描述. Output 一行一个整数代表答案. Sample Input 2 10007 2 0 Sample Output 8 HINT 1 ≤ n ≤ 10^9, 0 ≤ r < k ≤ 50, 2 ≤ p ≤ 2^30 − 1 Solution 首先,不难发

JZYZOJ 1542 [haoi2015]str 矩阵乘法 dp

http://172.20.6.3/Problem_Show.asp?id=1542 dp+矩阵乘法思路hin好想,对于我这种题目稍微学术就几乎什么也不会的人来说唯一的难点在于读题,因为一心想着划水题目没有看清楚,样例wa了一会最后仔细读题发现自己g的操作看错了,非常智障了 代码 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #inclu

bzoj1009 [HNOI2008] GT考试 矩阵乘法+dp+kmp

1009: [HNOI2008]GT考试 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 4542  Solved: 2815[Submit][Status][Discuss] Description 阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字.他的不吉利数学A1A2...Am(0<=Ai<=9)有M位,不出现是指X1X2...Xn中没有恰好一段等于A1A2..