HDU1005 一类递推矩阵优化

Problem Address:http://acm.hdu.edu.cn/showproblem.php?pid=1005


【题意】


f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7

1 <= A, B <= 1000, 1 <= n <= 100,000,000


【思路】


由于这道题只需要mod7,所以可以用循环节之类的方法做。

但也可以用矩阵优化递推的方法简单地做出来。

下面描述一下矩阵的做法。


f(n+2) = A*C(n-1)*B(1)

其中A、B、C均为矩阵。

A=

(a1,a2)

B=

(1)

(2)

C=

(a1, a2)

(1 , 0 )

关键部分是算出C的n-1次方,得出结果后再由上式计算出f(n+2)的值,而f(1)、f(2)的值为已知。

详细请参考:http://wenku.baidu.com/view/b396f5c689eb172ded63b7b8.html


C(n)可以使用快速幂的形式计算。矩阵的快速幂类似于普通整数的快速幂。

为了方便,可以定义矩阵的结构体,重载乘法以及幂运算的运算符。

具体看代码。


【代码】


#include <iostream>
using namespace std;

const int P = 7;

struct matrix
{
	int mat[2][2];
	int N;
	void init(int a, int b)
	{
		N = 2;
		mat[0][0] = a;		mat[0][1] = b;
		mat[1][0] = 1;		mat[1][1] = 0;
	}
	matrix operator *(matrix B)
	{
		matrix C;
		C.N = N;
		memset(C.mat, 0, sizeof(C.mat));
		int i, j, k;
		for (i=0; i<N; i++)
		{
			for (j=0; j<N; j++)
			{
				if (mat[i][j])
				{
					for (k=0; k<N; k++)
					{
						C.mat[i][k] = (C.mat[i][k]+mat[i][j]*B.mat[j][k])%P;
					}
				}
			}
		}
		return C;
	}
	matrix operator ^ (int n)
	{
		matrix C;
		C.N = N;
		memset(C.mat, 0, sizeof(C.mat));
		int i;
		for (i=0; i<N; i++) C.mat[i][i] = 1;
		while(n)
		{
			if (n&1) C = C*(*this);
			*this = (*this)*(*this);
			n >>= 1;
		}
		return C;
	}
	int getvalue(int a1, int a2, int a, int b)
	{
		return (a2*(a*mat[0][0]+b*mat[1][0])+a1*(a*mat[0][1]+b*mat[1][1]))%P;//这里本来的a1和a2位置颠倒了,现已改过来
	}
};

int solve(int a1, int a2, int a, int b, int n)
{
	if (n==1) return a1;
	else if (n==2) return a2;
	n -= 2;
	matrix A;
	A.init(a, b);
	A = A^(n-1);
	return A.getvalue(a1, a2, a, b);
}

int main()
{
	int a, b, n;
	while(scanf("%d %d %d", &a, &b, &n)!=EOF)
	{
		if (n==0 && a==0 && b==0) break;
		printf("%d\n", solve(1, 1, a, b, n));
	}
	return 0;
}


注:之前由于是直接使用斐波那契数列,a1=a2=1,所以没有发现错误。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值