hdu A Simple Math Problem 1757 矩阵的构造和快速幂

本文介绍了如何使用矩阵乘法解决一种递推关系问题,通过矩阵的构造和快速幂算法,有效计算函数f(x)的值。讨论了矩阵乘法的条件、结合律,并详细解释了快速幂的原理及其优化时间复杂度的方式。

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

一道矩阵乘法的题目,做了这道题,让我稍微开拓了一点点思维。题意很简单,给你一个函数,如果x <10,f(x) = x;

如果x > 10, f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + …… + a9 * f(x-10); a0,a1。。。。a9是常数,题目输入会给出。

做这个题目首先了解下矩阵。有两个矩阵A B,他们的乘积也是一个矩阵C,c[i][j]等于A矩阵第i行与B矩阵的第j列每个元素乘积的和。

例如A =  a1 a2   B = b1 b2    ,那么c = (a1 * b1 + a2 * b3) (a1 *b2 + a2 * b4)

                a3 a4          b3 b4                        (a3 * b1 + a4 * b3)    (a3 * b2 + a4 * b4)

所以两个矩阵A B能相乘,必须要A的列数等于B的行数。

将递推式化为矩阵 ,为了简便,假设只有4个元素:


         a0 a1 a2 a3             f(x-1)                                                       f(x)

A =   1   0   0   0       B =    f(x-2)              他们相乘得到矩阵c  =  f(x-1)

         0   1   0   0                f(x-3)                                                      f(x-2)

         0   0   1   0               f(x-4)                                                        f(x-3)

可以看到,A B相乘都能得到一个新的矩阵c,c比b中多了一个未知量f(x),再将A与c相乘,又可以得到一个新的矩阵d,d中比c多了一个f(x+1)

这样连乘几次,就能得到f(n)

同时矩阵乘法满足结合律,我们可以先将A连乘n - 10次,相当于A^(n-10)再乘以矩阵B,就可以得到我们要的答案了。

再简单的讲讲快速幂.

如果b是偶数,a^b是不是等于 (a^2)^(b/2)?例如2的8次方是不是等于2的平方的4次方?(2^8 = (2^2)^4 = 4^4),这样每次就可以将b减小一般,时间复杂度为O(logb)

如果b是奇数,那么我们就让结果ans 乘以一个a,就消去了a的一个次方

#include<stdio.h>
#include<memory>
using namespace std;

int a[10][10],ans[10][10],m;

void multi(int a[10][10],int b[10][10])//做矩阵A与矩阵A的乘法
{
	int c[10][10];
	for(int i = 0;i < 10;++i)
		for(int j = 0;j < 10;++j)
		{
			int sum = 0;
			for(int k = 0;k < 10;++k)
				sum += a[i][k] * b[k][j];
			c[i][j] = sum % m;
		}
	memcpy(a,c,sizeof(c));
}

int main()
{
	int n,c[10];
	while(scanf("%d%d",&n,&m) != EOF)
	{
		for(int i = 0;i < 10;++i)
			scanf("%d",&c[i]);
		memset(a,0,sizeof(a));
		memset(ans,0,sizeof(ans));
		for(i = 0;i < 10;++i)
			a[0][i] = c[i];
		for(i = 1;i < 10;++i)
		{
			a[i][i-1] = 1;
			ans[i][i] = 1;
		}
		ans[0][0] = 1;
		if(n < 10)
		{
			printf("%d\n",n);
			continue;
		}
		n -= 9;
		while(n > 1)
		{
			if(n&1)//如果n是奇数,就让结果乘以a
				multi(ans,a);
			multi(a,a);//让a * a,相当于 a = a*a
			n >>= 1;
		}
		multi(ans,a);
		int sum = 0;
		for(i = 0;i < 10;++i)
		{
			sum += ans[0][i] * (10 - i - 1);
			sum %= m;
		}
		printf("%d\n",sum%m);
	}
	return 0;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值