poj Matrix Power Series 3233 (矩阵快速幂&二分)好题

本文介绍了一种利用矩阵快速幂方法求解矩阵幂级数S=A+A²+A³+...+Ak的算法。该算法通过二分法将问题规模减半,并根据不同情况递归求解,最终输出模m后的矩阵S。

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

Matrix Power Series
Time Limit: 3000MS Memory Limit: 131072K
Total Submissions: 19132 Accepted: 8070

Description

Given a n × n matrix A and a positive integer k, find the sum S = A + A2 + A3 + … + Ak.

Input

The input contains exactly one test case. The first line of input contains three positive integers n (n ≤ 30), k (k ≤ 109) and m (m < 104). Then follow n lines each containing n nonnegative integers below 32,768, giving A’s elements in row-major order.

Output

Output the elements of S modulo m in the same way as A is given.

Sample Input

2 2 4
0 1
1 1

Sample Output

1 2
2 3
思路:运用数学二分
对k进行二分,每次将规模减半,分k为奇偶两种情况,如当k = 6和k = 7时有:
      k = 6 有: S(6) = (1 + A^3) * (A + A^2 + A^3) = (1 + A^3) * S(3)。
      k = 7 有: S(7) = A + (A + A^4) * (A + A^2 + A^3) = A + (A + A^4) * S(3)。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define INF 0x3f3f3f3f
#define ll long long
#define N 50
using namespace std;
struct mat
{
	ll m[N][N];
};
int n,k,M;
mat matadd(mat a,mat b)//矩阵相加 
{
	int i,j;
	mat c;
	for(i=0;i<n;i++)
	{
		for(j=0;j<n;j++)
		{
			c.m[i][j]=(a.m[i][j]+b.m[i][j])%M;
		}
	}
	return c;
}
mat multi(mat a,mat b)//矩阵相乘 
{
	int i,j,k;
	mat c;
	for(i=0;i<n;i++)
	{
		for(j=0;j<n;j++)
		{
			c.m[i][j]=0;
			for(k=0;k<n;k++)
			{
				c.m[i][j]=(a.m[i][k]*b.m[k][j]+c.m[i][j])%M; 
			}
		}
	}
	return c;
}
mat power(mat A,int k)//矩阵快速幂 
{
	if(!k)
	{
		memset(A.m,0,sizeof(A.m));
		for(int i=0;i<n;i++)
			A.m[i][i]=1;
		return A;
	}
	if(k==1)
		return A;
	mat c=power(A,k/2);
	if(k%2==0)
		return multi(c,c);
	else
		return multi(multi(c,c),A);
}
mat matcal(mat A,int k)// 求S (k) = A + A2 + A3 + … + Ak
{
	if(k==1)
		return A;
	mat b=power(A,(k+1)/2);
	mat c=matcal(A,k/2);
	if(k%2==0)
		return multi(matadd(power(A,0),b),c);// 如S(6) = (1 + A^3) * S(3)
	else
		return matadd(A,multi(matadd(A,b),c));// 如S(7) = A + (A + A^4) * S(3)
}
int main()
{
	int i,j;
	mat A;
	scanf("%d%d%d",&n,&k,&M);
	for(i=0;i<n;i++)
	{
		for(j=0;j<n;j++)
		{
			scanf("%lld",&A.m[i][j]);
		}
	}
	A=matcal(A,k);
	for(i=0;i<n;i++)
	{
		for(j=0;j<n;j++)
		{
			printf(j?" %lld":"%lld",A.m[i][j]);
		}
		printf("\n");
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值