POJ 3233 Matrix Power Series(矩阵快速幂前缀和)

题意:给出一个矩阵A求 S = A + A2 + A3 + … + Ak.

思路:矩阵快速幂最重要的就是转移过程的实现,由当前状态转移到下一个状态的中间变化即使转移矩阵。

这道题目由两种解法:
1.直接找出S 和An关系

先看看前面几个 S2=S1+A2 S3=S2+A3

Sn                    E        E                 Sn-1
             =                                      
A^(n+1)               0        A                 A^n

这里我们直接把矩阵行列扩大一倍就可以直接做了

#include<stdio.h>
#include<iostream>
#include<cmath>
#include<string.h>
#define fi first
#define se second
#define log2(a) log(n)/log(2)
#define show(a) cout<<a<<endl;
#define show2(a,b) cout<<a<<" "<<b<<endl;
#define show3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl;
using namespace std;

typedef long long ll;

const ll inf = 1e17 + 10;
const int N = 1e6 + 10;
const ll mod = 1e9+7;
const int base=131;
const double pi=acos(-1);




int n,m,k;

struct mat{
	ll x[70][70];
	mat(){memset(x,0,sizeof x);}
};

mat mul(mat a,mat b)
{
	mat ans;
	for(int i=1;i<=2*n;i++)
	{
		for(int j=1;j<=2*n;j++)
		{
			for(int k=1;k<=2*n;k++)
			{
				ans.x[i][j]=(ans.x[i][j]+a.x[i][k]*b.x[k][j])%m;
			}
		}
	}
	return ans;
}

mat ksm(mat x,ll k)
{
	mat ans;
	for(int i=1;i<=2*n;i++) ans.x[i][i]=1;
	while(k)
	{
		if(k&1) ans=mul(ans,x);
		k>>=1;
		x=mul(x,x);
	}

	return ans;
}
int main( )
{

	ios::sync_with_stdio(false);
	cin.tie(0);

	cin>>n>>k>>m;
	mat ans,tr,a;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			cin>>a.x[i][j];
			tr.x[i+n][j+n]=ans.x[i][j]=a.x[i][j];
		}
	}
	a=mul(a,a);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			ans.x[i+n][j]=a.x[i][j];
		}
	}

	for(int i=1;i<=n;i++)
	{
		tr.x[i][i]=tr.x[i][i+n]=1;
	}

	ans=mul(ksm(tr,k-1),ans);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<n;j++)
		{
			cout<<ans.x[i][j]<<" ";
		}
		cout<<ans.x[i][n]<<endl;
	}



}

POJ 3233 Matrix Power Series(矩阵快速幂前缀和)

方法二:
POJ 3233 Matrix Power Series(矩阵快速幂前缀和)
就是通过不断的二分操作,按照如图判断n的奇偶性,进行上述公式的求和,显然这种方法会慢许多。

#include<stdio.h>
#include<iostream>
#include<cmath>
#include<string.h>
#define fi first
#define se second
#define log2(a) log(n)/log(2)
#define show(a) cout<<a<<endl;
#define show2(a,b) cout<<a<<" "<<b<<endl;
#define show3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl;
using namespace std;

typedef long long ll;

const ll inf = 1e17 + 10;
const int N = 1e6 + 10;
const ll mod = 1e9 + 7;
const int base = 131;
const double pi = acos ( -1 );




int n, m, k;
struct mat
{
	ll x[35][35];
	mat()
	{
		memset ( x, 0, sizeof x );
	}
};

mat ans, tr, a;

mat mul ( mat a, mat b )
{
	mat ans;
	for ( int i = 1; i <= n; i++ )
	{
		for ( int j = 1; j <= n; j++ )
		{
			for ( int k = 1; k <= n; k++ )
			{
				ans.x[i][j] = ( ans.x[i][j] + a.x[i][k] * b.x[k][j] ) % m;
			}
		}
	}
	return ans;
}
mat add ( mat a, mat b )
{
	mat ans;
	for ( int i = 1; i <= n; i++ )
	{
		for ( int j = 1; j <= n; j++ )
		{
			ans.x[i][j] = ( a.x[i][j] + b.x[i][j] ) % m;

		}
	}
	return ans;
}
mat ksm ( mat x, ll k )
{
	mat ans;
	for ( int i = 1; i <= n; i++ ) ans.x[i][i] = 1;
	while ( k )
	{
		if ( k & 1 ) ans = mul ( ans, x );
		k >>= 1;
		x = mul ( x, x );
	}
	return ans;
}

mat solve ( int k )
{
	if ( k == 1 ) return a;
	mat s = solve ( k / 2 );

	mat tmp = ksm ( a, k / 2 );

	mat q = mul ( tmp, s );

	s = add ( s, q );

	if ( k & 1 )
	{
		s = add ( s, ksm ( a, k ) );
	}
	return s;
}
int main( )
{

	ios::sync_with_stdio ( false );
	cin.tie ( 0 );

	cin >> n >> k >> m;
	for ( int i = 1; i <= n; i++ )
	{
		for ( int j = 1; j <= n; j++ )
		{
			cin >> a.x[i][j];

		}
	}
	ans = solve ( k );
	
	for ( int i = 1; i <= n; i++ )
	{
		for ( int j = 1; j < n; j++ )
		{
			cout << ans.x[i][j] << " ";
		}
		cout << ans.x[i][n] << endl;
	}

}

POJ 3233 Matrix Power Series(矩阵快速幂前缀和)