HDU 1757 A Simple Math Problem(矩阵快速幂)

本文介绍了如何通过矩阵快速幂的方法解决一个基于类斐波那契数列的复杂数学问题。重点在于理解公式背后的数学原理,并提供了一段高效的代码实现,演示如何将矩阵操作应用于快速幂计算,以达到高效求解目标。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

Lele now is thinking about a simple function f(x).

If x < 10 f(x) = x.
If x >= 10 f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + …… + a9 * f(x-10);
And ai(0<=i<=9) can only be 0 or 1 .

Now, I will give a0 ~ a9 and two positive integers k and m ,and could you help Lele to caculate f(k)%m.
 

Input

The problem contains mutiple test cases.Please process to the end of file.
In each case, there will be two lines.
In the first line , there are two positive integers k and m. ( k<2*10^9 , m < 10^5 )
In the second line , there are ten integers represent a0 ~ a9.
 

Output

For each case, output f(k) % m in one line.
 

Sample Input

10 9999 1 1 1 1 1 1 1 1 1 1 20 500 1 0 1 0 1 0 1 0 1 0
 

Sample Output

45 104


题意很简单,公式给出来了,不过找循环节的话不太靠谱,应该可以,可是没去细想。这道题的公式是类似斐波那契数列的,所以用矩阵快速幂妥妥可以解出来。

本题用矩阵求解公式如下:


这个公式是由以下公式推导而来的:


只要先求出后面的方阵的幂,然后再求fn即可。

只要是类似斐波那契的数列都可以用上面的公式变形求得。

至于矩阵可以写一个结构体或者类,然后重载一下*和%就可以直接套用快速幂的模板了,本题的快速幂是位运算模式的,所以就直接重载掉^了


代码:

#include<iostream>
using namespace std;

int M;

class mat
{

	
public:
int num[10][10];
	void sete()
	{
		for (int i = 0; i<10; i++)
		for (int j = 0; j<10; j++)
		{
			if (i == j) num[i][j] = 1;
			else num[i][j] = 0;
		}
	}
	void setone(int *a)
	{
		for (int i = 0; i<10; i++)
			num[0][i] = a[i];
		for (int i = 1; i<10; i++)
		for (int j = 0; j<10; j++)
		{
			if (i - 1 == j) num[i][j] = 1;
			else num[i][j] = 0;
		}
	}
	mat operator * (const mat& ano)
	{
		mat ans;
		for (int i = 0; i<10; i++)
		{
			for (int j = 0; j<10; j++)
			{
				ans.num[i][j]=0;
				for (int k = 0; k<10; k++)
				ans.num[i][j] += (((this->num)[i][k])*((ano.num)[k][j])%M);
				
				ans.num[i][j]=ans.num[i][j]%M;
			}	
		}		
		return ans;
	}
	mat operator %(int m)
	{
		mat ans;
		for (int i = 0; i<10; i++)
		for (int j = 0; j<10; j++)
			ans.num[i][j] = this->num[i][j] % m;
		return ans;
	}
	mat operator ^(int b) 
	{
		mat a = *this;
		mat res;
		res.sete();
		while (b) {
			if (b & 1)
				res = res * a;
			a = a * a;
			b >>= 1;
		}
		return res;
	}
};

int basenum[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

int main()
{
	int a[10];
	int k;
	while (cin >> k >> M)
	{
		for (int i = 0; i<10; i++)
			cin >> a[i];
		if (k<10)
		{
			cout << basenum[k] % M << endl;
			continue;
		}
		mat one;
		one.setone(a);
		mat two;
		two = one^(k-9);
		int ans = 0;
		for (int i = 0; i < 10; i++)
			ans = (ans + two.num[0][i]*(9-i)) % M;
		cout << ans % M << endl;
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值