矩阵十题【七】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[2]+f[1]=3;

f[4]=f[3]+f[2]=5;

当k=3,    f[1]=1;

f[2]=f[1]+f[0]=2;

f[3]=f[2]+f[1]+f[0]=4;

f[4]=f[3]+f[2]+f[1]=7;

k的数据量只有10,所以我们构造出一个10*10的矩阵,本题主要考察的是矩阵快速幂以及构造这个矩阵。

若k等于4

【 [ 0  1  0  0]          [f(k-4)]       [f(k-3)]

[ 0  0  1  0]     *    [f(k-3)]   =  [f(k-2)]

[ 0  0  0  1]          [f(k-2)]       [f(k-1)]

[ 1  1  1  1] 】      [f(k-1)]       [f( k )]

根据上面的例子我们可以很容易构造出这个矩阵出来。

#include<stdio.h>
#include<string.h>
#define N 11
#define M 7777777
struct Matrix
{
    __int64 a[N][N];
}res,tmp,origin,A,ans;
int n,m,f[N];
Matrix mul(Matrix x,Matrix y)
{
    int i,j,k;
    memset(tmp.a,0,sizeof(tmp.a));
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
            for(k=1;k<=n;k++)
            {
                tmp.a[i][j]+=(x.a[i][k]*y.a[k][j])%M;
                tmp.a[i][j]%=M;
            }
    return tmp;
}
void quickpow(int k)  //矩阵快速幂
{
    int i;
    memset(res.a,0,sizeof(res.a));
    for(i=1;i<=n;i++)
        res.a[i][i]=1;
    while(k)
    {
        if(k&1)
            res=mul(res,A);
        A=mul(A,A);
        k>>=1;
    }
}
int main()
{
    int k,i,j;
    while(scanf("%d%d",&k,&m)!=EOF)
    {
        memset(f,0,sizeof(f));
        f[0]=1;
        for(i=1;i<=k;i++)      //构造前k项
            for(j=0;j<i;j++)
                f[i]+=f[j];
        memset(A.a,0,sizeof(A.a));
        for(i=2;i<=k;i++)      //构造矩阵A
            A.a[i][i-1]=1;
        for(i=1;i<=k;i++)
            A.a[i][k]=1;
        n=k;
        quickpow(m-k);   //A^(n-k)
        memset(origin.a,0,sizeof(origin.a));
        for(i=1;i<=k;i++)     //前k项的矩阵[f(1),f(2),f(3)....f(k)]
            origin.a[1][i]=f[i];
        ans=mul(origin,res);      //[f(1),f(2),f(3)....f(k)] * A^(n-k)
        printf("%d\n",ans.a[1][n]%M);
    }
    return 0;
}

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

时间: 2024-11-08 05:39:04

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

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

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 守望者的烦恼(矩阵加速递推)

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

[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

[矩阵乘法][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方程进行优化. 仔细观察转移方程会发现,每次都是加上

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=

矩阵十题【五】 VOJ1049 HDU 2371 Decode the Strings

题目链接:https://vijos.org/p/1049 题目大意:顺次给出m个置换,反复使用这m个置换对初始序列进行操作,问k次置换后的序列.m<=10, k<2^31. 首先将这m个置换"合并"起来(算出这m个置换的乘积),然后接下来我们需要执行这个置换k/m次(取整,若有余数则剩下几步模拟即可).注意任意一个置换都可以表示成矩阵的形式.例如,将1 2 3 4置换为3 1 2 4,相当于下面的矩阵乘法: 置换k/m次就相当于在前面乘以k/m个这样的矩阵.我们可以二分计

矩阵十题【三】 HDU 1588 Gauss Fibonacci

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1588 题目大意:先要知道一组斐波那契数列 i 0 1 2 3 4 5 6 7 f(i) 0 1 1 2 3 5 8 13 下面给你一组数: k,b,n,M 现在知道一组公式g(i)=k*i+b:(i=0,1,2,3...n-1) 让你求出 f(g(i)) 的总和(i=01,2,3,...,n-1),比如给出的数据是2 1 4 100 2*0+1=1   f(1)=1 2*1+1=3   f(3)=2

矩阵十题【一】

题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=298 题目大意:已知n个点(n<10000),现在对所有点进行以下操作: 平移一定距离(M),相对X轴上下翻转(X),相对Y轴左右翻转(Y),坐标缩小或放大一定的倍数(S),所有点对坐标原点逆时针旋转一定角度(R). 操作的次数不超过1000000次,求最终所有点的坐标. 首先我们要知道矩阵乘法的概念. 在数学中,一个矩阵说穿了就是一个二维数组.一个n行m列的矩阵可以乘以一个m行p列的矩