矩陣冪之和(矩陣乘法)

2481. [HZOI 2016][POJ3233]矩陣冪之和

時間限制:2 s   內存限制:128 MB

【題目描述】

給定一個n*n的矩陣A和一個正整數k,求S=A+A^2+A^3+...+A^k。

【輸入格式】

第一行三個正整數n,k,m。

以下n行,每行n個小於m的非負整數,表示矩陣A。

【輸出格式】

n行,每行n個數,表示矩陣S中的每個元素mod m的值。

【樣例輸入】

2 2 4
0 1
1 1

【樣例輸出】

1 2
2 3

【數據範圍與約定】

對於30%的數據,k<=10^5。

對於60%的數據,m<=10^8。

對於100%的數據,n<=30,k<=10^10,m<=10^18。


剛看這題想到了之前做的一道題,求得是一個數的A+A^2+A^3+...+A^k之和,那個可以用錯位相減和乘法逆元來搞,然而這個不行(難道逆矩陣?滑稽)。

首先我們把初始矩陣設爲A,單位矩陣設爲E,零矩陣設爲O,構造出這樣一個矩陣:

A E    一次冪: A^2 A+E  二次冪:A^3  A^2+A+E  三次冪: A^4  A^3+A^2+A+E

O E             O   E            O    E                 O    E

那麼我們會驚奇的發現,這個矩陣的K+1次冪居然是E+A+A^2+A^3+...+A^k,那麼我們再減去一個E就是最終結果。(沒錯,就是矩陣套矩陣.) 這個題應該還有別的更快的做法,不過個人感覺好複雜的樣子。

注意:乘法爆long long,要處理一下。。。

代碼:

#include<cstdio>
#include<iostream>
#include<cstring>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
int n;
ll K,ki;
inline ll mul(ll x,ll y){return (x*y-(ll)(x/(long double)ki*y+1e-3)*ki+ki)%ki;}
struct matrix
{	ll s[32][32];
	matrix(){mem(s,0);}
	void init(){mem(s,0);for(int i=0;i<n;i++) s[i][i]=1;}
	void cl(){mem(s,0);}
	friend matrix operator * (matrix x,matrix y)
	{	matrix z;ll tmp;
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				for(int k=0;k<n;k++)
				{	tmp=mul(x.s[i][k],y.s[k][j])%ki;
					z.s[i][j]+=tmp;z.s[i][j]%=ki;
				}
		return z;
	}
	friend matrix operator + (matrix x,matrix y)
	{	matrix z;
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				z.s[i][j]=(x.s[i][j]+y.s[i][j])%ki;
		return z;
	}
	friend matrix operator - (matrix x,matrix y)
	{	matrix z;
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				z.s[i][j]=(x.s[i][j]-y.s[i][j]+ki)%ki;
		return z;
	}
}A,E,O,fans;
struct matrix2
{	matrix s[4][4];
	void cl(){for(int i=0;i<2;i++) for(int j=0;j<2;j++) s[i][j].cl();}
	matrix2(){cl();}
	void init(){for(int i=0;i<2;i++) s[i][i].init();}
	friend matrix2 operator * (matrix2 x,matrix2 y)
	{	matrix2 z;
		for(int i=0;i<2;i++)
			for(int j=0;j<2;j++)
				for(int k=0;k<2;k++)
				{	matrix tmp=x.s[i][k]*y.s[k][j];
					z.s[i][j]=z.s[i][j]+tmp;
				}
		return z;
	}
}B,ans;
int main()
{   	freopen("matrix_sum.in","r",stdin);
	freopen("matrix_sum.out","w",stdout);
	scanf("%d%lld%lld",&n,&K,&ki);
	ll tmp;E.init();ans.init();
	for(int i=0;i<n;i++)
		for(int j=0;j<n;j++)
		{	scanf("%lld",&tmp);
			A.s[i][j]=tmp;
		}
	B.s[0][0]=A;B.s[0][1]=E;B.s[1][0]=O;B.s[1][1]=E;
	ll edg=K+1;
	for(;edg;edg>>=1,B=B*B)
		if(edg&1) ans=ans*B;
	fans=ans.s[0][1]-E;
	for(int i=0;i<n;i++)
	{	printf("%lld",fans.s[i][0]);
		for(int j=1;j<n;j++)
			printf(" %lld",fans.s[i][j]);
		putchar('\n');
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章