关闭

POJ - 3233 Matrix Power Series

标签: 快速幂矩阵快速幂
1500人阅读 评论(0) 收藏 举报
分类:

题目:

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 nnonnegative 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

有个题目和这个很像,点击打开我的博客

和那个题目一样,这个题目我也有2种思路。

第一种思路:用S(k/2)求S(k),快速幂

超时的代码:

#include<iostream>
using namespace std;

int n, k, m;
long long in[30][30];
long long list[30][30];
long long temp[30][30];
long long sum[30][30];

void pro(long long l1[][30], long long l2[][30], long long t[][30])	//t=l1*l2
{
	for (int i = 0; i < n; i++)for (int j = 0; j < n; j++)
	{
		t[i][j] = 0;
		for (int k = 0; k < n; k++)t[i][j] = (t[i][j] + l1[i][k]%m * l2[k][j]%m) % m;
	}
}

void f(int num)		//list=in^num
{
	if (num == 1)
	{
		for (int i = 0; i < n; i++)for (int j = 0; j < n; j++)
			list[i][j] = in[i][j] % m;
		return;
	}
	f(num / 2);
	pro(list, list, temp);
	if (num % 2)pro(temp, in, list);
	else for (int i = 0; i < n; i++)for (int j = 0; j < n; j++)list[i][j] = temp[i][j];
}

void getsum(int num)	
{
	if (num == 1)
	{
		for (int i = 0; i < n; i++)for (int j = 0; j < n; j++)sum[i][j] = in[i][j]%m;
		return;
	}
	getsum(num / 2);
	f(num / 2);
	pro(sum, list, temp);
	for (int i = 0; i < n; i++)for (int j = 0; j < n; j++)
		sum[i][j] = (sum[i][j] + temp[i][j]) % m;
	if (num % 2)
	{
		pro(sum, in, temp);
		for (int i = 0; i < n; i++)for (int j = 0; j < n; j++)
			sum[i][j] = (temp[i][j] + in[i][j]) % m;
	}
}

int main()
{
	cin >> n >> k >> m;
	for (int i = 0; i < n; i++)for (int j = 0; j < n; j++)cin >> in[i][j];
	getsum(k);
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			if (j)cout << " ";
			cout << sum[i][j];
		}
		cout << endl;
	}
	return 0;
}

这个代码的时间是(log k)^2 / 2 * n*n

这个我感觉不太大才对,毕竟只有1组数据,但是超时了。

我知道矩阵快速幂的效率更高,于是看这个能不能过。


第二种思路:用S(k-1)求S(k),矩阵快速幂

S(k)=S(k-1)*A +A



下面的代码中in就是中间这个大矩阵。

只需要求出list=in^k 即可求出S(k)

假设


那么

S(k)=CA

其中C可以从list的右上角抠出来,A可以从in的左上角抠出来。

代码:

#include<iostream>
using namespace std;

int n, k, m;
long long in[60][60];
long long list[60][60];
long long temp[60][60];

void pro(long long l1[][60], long long l2[][60], long long t[][60])	//t=l1*l2
{
	for (int i = 0; i < n*2; i++)for (int j = 0; j < n*2; j++)
	{
		t[i][j] = 0;
		for (int k = 0; k < n * 2; k++)t[i][j] = (t[i][j] + l1[i][k] * l2[k][j]) % m;
	}
}
void f(int num)		//list=in^num
{
	if (num == 0)
	{
		for (int i = 0; i < n*2; i++)for (int j = 0; j < n*2; j++)
			list[i][j] = (i == j);
		return;
	}
	f(num / 2);
	pro(list, list, temp);
	if (num % 2)pro(temp, in, list);
	else for (int i = 0; i < n*2; i++)for (int j = 0; j < n*2; j++)list[i][j] = temp[i][j];
}

int main()
{
	cin >> n >> k >> m;
	for (int i = 0; i < n * 2; i++)for (int j = 0; j < n * 2; j++)
		in[i][j] = (i == j || i+n == j );
	for (int i = 0; i < n; i++)for (int j = 0; j < n; j++)cin >> in[i][j];
	f(k);
	long long r;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			if (j)cout << " ";
			r = 0;
			for (int k = 0; k < n; k++)r += list[i][k + n] * in[k][j];
			cout << r%m;
		}
		cout << endl;
	}
	return 0;
}

这个代码的时间是,log k *(n*2)*(n*2)

这个代码是922ms AC的,前面的代码大约是4倍的时间,也就是大约4s,限时是3s,难怪过不了。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:967261次
    • 积分:18131
    • 等级:
    • 排名:第576名
    • 原创:772篇
    • 转载:0篇
    • 译文:0篇
    • 评论:109条
    博客专栏