HDU5015_233 Matrix(矩阵快速幂,递推转矩阵)

题意:

给定矩阵的第一行和第一列,其余每项 a [ i ] [ j ] = a [ i − 1 ] [ j ] + a [ i ] [ j − 1 ] a[i][j] = a[i-1][j] + a[i][j-1] a[i][j]=a[i1][j]+a[i][j1],求 a n , m % 10000007 a_{n,m}\% 10000007 an,m%10000007

数据范围:

n < = 10 , m < = 1 0 9 , 0 < = a 1 , 0 , a 2 , 0 , . . . , a n , o < 2 31 n<=10,m<=10^9,0<=a_{1,0},a_{2,0},...,a_{n,o}<2^{31} n<=10,m<=1090<=a1,0,a2,0,...,an,o<231

思路:

首先第0行为0, 233, 23333...,为了使递推式 a 0 , j = 10 ∗ a 0 , j − 1 + 3 a_{0,j}=10*a_{0,j-1}+3 a0,j=10a0,j1+3成立,把第一个0变为23,即 a 0 , 0 a_{0,0} a0,0视作23。

  • 第 0 行, a 0 , j = 10 a 0 , j − 1 + 3 a_{0,j}=10a_{0,j-1}+3 a0,j=10a0,j1+3
  • 第 1 行, a 1 , j = a 1 , j − 1 + a 0 , j = a 1 , j − 1 + 10 a 0 , j − 1 + 3 a_{1,j}=a_{1,j-1}+a_{0,j}=a_{1,j-1}+10a_{0,j-1}+3 a1,j=a1,j1+a0,j=a1,j1+10a0,j1+3
  • 第 2 行, a 2 , j = a 2 , j − 1 + a 1 , j = a 2 , j − 1 + a 1 , j − 1 + 10 a 0 , j − 1 + 3 a_{2,j}=a_{2,j-1}+a_{1,j}=a_{2,j-1}+a_{1,j-1}+10a_{0,j-1}+3 a2,j=a2,j1+a1,j=a2,j1+a1,j1+10a0,j1+3
  • … …
  • 第 n 行, a n , j = ∑ i = 1 n a i , j − 1 + 10 a 0 , j − 1 + 3 a_{n,j}=\sum_{i=1}^{n}a_{i,j-1}+10a_{0,j-1}+3 an,j=i=1nai,j1+10a0,j1+3
    重点是怎么构造矩阵呢?
    线代知识,把等式左边构成一列向量,等式右边的系数就是系数矩阵(也就是所要求的构造矩阵)。当时在求大数fibonacci项时, f n = f n − 1 + f n − 2 f_n=f_n{-1}+f_{n-2} fn=fn1+fn2只需构造一个2*2矩阵即可。而这里最后存在非线性项+3,要给左边的列向量,n + 1 行增广一个常数 1,共 n + 2 行

将上面的递推写成矩阵形式
在这里插入图片描述
可以看出后一列可由前一列递推得来。要求 a n , m a_{n,m} an,m,也就是第 m 列的情况,递推得:
在这里插入图片描述
矩阵的 m 次幂可用矩阵快速幂解决。
最后 a n , m = ∑ j = 0 n + 1 a n s [ n ] [ j ] ∗ c o l [ j ] a_{n,m}=\sum_{j=0}^{n+1}ans[n][j] * col[j] an,m=j=0n+1ans[n][j]col[j]

input:
1 1
1
2 2
0 0
3 7
23 47 16
output:
234
2799
72937

#include<cstdio>
#include<iostream>
#include<cstring> 
using namespace std;
typedef long long ll;
const int maxn=12; //矩阵最多 12 阶 
const int MOD=10000007;
int col[maxn]; //矩阵第一列 
int n,m;
struct matrix{
	ll a[maxn][maxn];
	void init()
	{
		memset(a,0,sizeof a);
		for(int i = 0; i < n + 2; i++)
			a[i][i] = 1;
	} 
};
matrix mul(matrix p, matrix q)
{
	matrix ans;
	for(int i = 0; i < n + 2; i++)
	{
		for(int j = 0; j < n + 2; j++)
		{
			ans.a[i][j] = 0;
			for(int k = 0; k < n + 2; k++)
				ans.a[i][j] = (ans.a[i][j] + p.a[i][k] * q.a[k][j])%MOD;
		}
	}
	return ans;
}
matrix qpow(matrix tag, int k)  //矩阵快速幂 
{
	matrix ans;
	ans.init();
	while(k)
	{
		if(k&1)
			ans = mul(ans, tag);
		tag = mul(tag, tag);
		k>>=1;
	}
	return ans;
}
int main()
{
	while(cin>>n>>m)
	{
		col[0]=23; //输入第一列 
		for(int i = 1; i <= n; i++)
			cin>>col[i];
		col[n+1]=1;
		
		matrix ans; //开始构造矩阵 
		ans.init();
		for(int i = 0; i <= n; i++) //纸上写好,往里填就可以
		{
			ans.a[i][0]=10;
			for(int j = 1; j <= i; j++)
				ans.a[i][j] = 1;
			ans.a[i][n+1] = 3;
			ans.a[n+1][i] = 0;
		}
		ans.a[n+1][n+1] = 1;
		
		ans = qpow(ans,m); //ans的 m 次幂 
		ll res = 0;
		for(int j = 0; j < n + 2; j++)  //第 n 行累加求和 
			res = (res + ans.a[n][j] * col[j])%MOD;
		cout<<res<<endl;
	}
	return 0;
}
《C++编程实例100篇》是一本深入实践、极具价值的编程教程,它针对C++编程语言提供了丰富的实例,旨在帮助读者更好地理解和掌握C++的各项特性与编程技巧。这本书的经典之处在于它将理论与实践相结合,通过100个精心设计的编程实例,覆盖了C++的各个核心领域,包括基础语法、面向对象编程、模板、异常处理、STL(标准模板库)等。 我们来探讨C++的基础语法。C++是C语言的增强版,它保留了C语言的高效性和灵活性,并引入了类、对象和继承等面向对象编程概念。基础语法包括变量声明、数据类型、运算符、控制结构(如if语句、for循环、while循环)、函数的定义和调用等。在实例中,你可能会遇到如何编写简单的程序,如计算两个数的和,或者实现一个简单的猜数字游戏。 C++的面向对象编程是其一大特色。通过类和对象,你可以构建复杂的软件系统。类是对象的蓝图,它定义了对象的属性和行为。实例化一个类,就是创建一个具体的对象。继承允许你创建新的类,这些类从现有的类派生,共享其属性和方法,同时可以添加新的功能。多态性是面向对象的另一个关键特性,它使得不同类型的对象可以对同一消息作出不同的响应。这些概念在实例中会以各种形式展现,例如设计一个图形界面的类层次,或实现一个简单的模拟游戏。 接下来是模板,C++的模板功能让代码更加通用,可以处理不同类型的数据。模板分为函数模板和类模板,前者可以创建泛型函数,后者可以创建泛型类。通过模板,你可以编写出高效且灵活的代码,比如实现一个通用的排序算法。 异常处理是C++中用于处理程序运行时错误的机制。当程序出现异常情况时,可以抛出一个异常,然后在适当的点捕获并处理这个异常。这使得代码能够优雅地处理错误,而不是让程序崩溃。实例中可能会有涉及文件操作或网络通信时可能出现的异常处理示例。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值