矩阵经典题目七: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

#include <stdio.h>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <stack>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#include <stdlib.h>
#include <algorithm>
#define LL long long
#define _LL __int64
#define eps 1e-12
#define PI acos(-1.0)
#define C 240
#define S 20
using namespace std;

const int maxn = 15;
const int mod = 7777777;

int k;
struct matrix
{
	_LL mat[maxn][maxn];
	void init()
	{
		memset(mat,0,sizeof(mat));
		for(int i = 1; i <= maxn; i++)
			mat[i][i] = 1;
	}
}a,b;

matrix mul(matrix a, matrix b)
{
	matrix ans;
	memset(ans.mat,0,sizeof(ans.mat));

	for(int i = 1; i <= k; i++)
	{
		for(int g = 1; g <= k; g++)
		{
			if(a.mat[i][g] == 0) continue;
			for(int j = 1; j <= k; j++)
			{
				ans.mat[i][j] = (ans.mat[i][j] + a.mat[i][g] * b.mat[g][j])%mod;
			}
		}
	}
	return ans;
}

matrix pow(matrix a, int n)
{
	matrix ans;
	ans.init();

	while(n)
	{
		if(n&1)
			ans = mul(ans,a);
		a = mul(a,a);
		n >>= 1;
	}
	return ans;
}

int main()
{
	int n;
	while(~scanf("%d %d",&k,&n))
	{
		memset(a.mat,0,sizeof(a.mat));

		for(int i = 1; i <= k-1; i++)
			a.mat[i][i+1] = 1;
		for(int i = 1; i <= k; i++)
			a.mat[k][i] = 1;

		matrix ans = pow(a,n-k);
		memset(b.mat,0,sizeof(b.mat));

		b.mat[0][1] = 1;
		for(int i = 1; i <= k; i++)
		{
			for(int j = 0; j < i; j++)
				b.mat[i][1] += b.mat[j][1];
		}
		ans = mul(ans,b);
		printf("%I64d\n",ans.mat[k][1]);
	}
	return 0;
}

矩阵经典题目七:Warcraft III 守望者的烦恼(矩阵加速递推),布布扣,bubuko.com

时间: 2024-10-25 11:58:22

矩阵经典题目七: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

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

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

矩阵十题【七】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

[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

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=

矩阵经典题目八:hdu 2175 How many ways??

http://acm.hdu.edu.cn/showproblem.php?pid=2157 给定一个有向图,问从A点恰好走k步(允许重复经过边)到达B点的方案数mod p的值 把给定的图转为邻接矩阵,即A(i,j)=1当且仅当存在一条边i->j.令C=A*A,那么C(i,j)=ΣA(i,k)*A(k,j),实际上就等于从点i到点j恰好经过2条边的路径数(枚举k为中转点).类似地,C*A的第i行第j列就表示从i到j经过3条边的路径数.同理,如果要求经过k步的路径数,我们只需要二分求出A^k即可.

矩阵经典题目四:送给圣诞夜的礼品(使用m个置换实现对序列的转变)

https://vijos.org/p/1049 给出一个序列,含n个数.然后是m个置换,求对初始序列依次进行k次置换,求最后的序列. 先看一个置换,把置换表示成矩阵的形式,然后将m个置换乘起来.那么初始序列首先执行这个置换k/m次,然后顺次执行前k%m个置换,最后乘上初始矩阵. 最后注意矩阵乘法的顺序,A*B != B*A. #include <stdio.h> #include <iostream> #include <map> #include <set&g

HDU 3117 Fibonacci Numbers(Fibonacci矩阵加速递推+公式)

题目意思很简单:求第n个Fibonacci数,如果超过八位输出前四位和后四位中间输出...,否则直接输出Fibonacci数是多少. 后四位很好求,直接矩阵加速递推对10000取余的结果就是. 前四位搜了一下:http://blog.csdn.net/xieqinghuang/article/details/7789908 Fibonacci的通项公式,对,fibonacci数是有通项公式的-- f(n)=1/sqrt(5)(((1+sqrt(5))/2)^n+((1-sqrt(5))/2)^n