poj 3233 --- Matrix Power Series (二分,矩阵)


Matrix Power Series
Time Limit: 3000MS Memory Limit: 131072K
Total Submissions: 9393 Accepted: 4018

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

Source

POJ Monthly--2007.06.03, Huang, Jinsong



Sk = A + A2 + A3 + … + Ak  

    =(1+Ak/2)*(A + A2 + A3 + … + Ak/2  )+{Ak}

    =(1+Ak/2)*(Sk/2 )+{Ak}// k为偶数时无 {Ak}

A  可用二分迭代求出


因此,只要求出 上面的三部分就可以求出 S

//800MS
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int m,n,K;
int a[30][30];
class Matrix
{
public:
    int num[30][30];
    Matrix(bool is=true)		//初始化
    {
        memset(num,0,sizeof(num));
		if(is)
		for(int i=0;i<n;i++)
			num[i][i]=1;
    }
    void print()				//输出函数
    {
        for(int i=0;i<n;++i)
        {
            printf("%d",num[i][0]);
            for(int j=1;j<n;++j)
                printf(" %d",num[i][j]);
            printf("\n");
        }
    }
	//重载乘法运算
   friend Matrix& operator *(const Matrix& max1,const Matrix& max2)
	{
		Matrix tmp(false);				//注意这里是false,即初始化的矩阵不是单位矩阵I
		for(int i=0;i<n;++i)
			for(int j=0;j<n;++j)
			{
				for(int k=0;k<n;++k)
					tmp.num[i][j]+=(max1.num[i][k]*max2.num[k][j])%m;
            tmp.num[i][j]%=m;
			}
		return tmp;
	}
   //重载+=运算
   Matrix& operator +=(const Matrix& max)
   {
	   for(int i=0;i<n;++i)
		   for(int j=0;j<n;++j)
			   num[i][j]=(num[i][j]+max.num[i][j])%m;

		return *this;
	}
}ans;
Matrix mul(Matrix A,int k)		//求A^K
{
	if(k==1)
		return A;
	Matrix tmp ;
	while(k)
	{
		if(k&1)
			tmp = tmp * A;
		k>>=1;
		A = A*A;
	}
	return tmp;
}
Matrix S(Matrix A,int k)		//求 S[k]
{
	if(k==1)
		return A;
	
	Matrix tmp ;
	tmp += mul(A,k>>1);			//求 (I + A^(k/2) )
	tmp = tmp*S(A,k>>1);		//求 (I + A^(k/2) )*S[k/2]
	if(k&1)						//判断时候要加上 A^k
		tmp+= mul(A,k);			//S[k] = (I+A^(k/2)) * S[k/2] + {A^k}
	return tmp;
} 

int main()
{
	int i,j,k;
    scanf("%d %d %d",&n,&K,&m);
    for( i=0;i<n;++i)
        for( j=0;j<n;++j)
            scanf("%d",&ans.num[i][j]);
	ans = S(ans,K);
	ans.print();

	return 0;
}



效率更高的代码1:


//266MS
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int m,n,K;
int a[30][30];
class Matrix
{
    public:
    int num[61][61];
    Matrix()
    {
        memset(num,0,sizeof(num));
    }
    void print()
    {
        for(int i=0;i<n;++i)
        {
            printf("%d",num[i][0]);
            for(int j=1;j<n;++j)
                printf(" %d",num[i][j]);
            printf("\n");
        }
        printf("\n");
    }
    friend Matrix& operator *(Matrix max1,Matrix max2);
};
Matrix& operator *(Matrix max1,Matrix max2)
{
    Matrix tmp;
    for(int i=0;i<2*n;++i)
        for(int j=0;j<2*n;++j)
        {
            for(int k=0;k<2*n;++k)
                tmp.num[i][j]+=(max1.num[i][k]*max2.num[k][j])%m;
            tmp.num[i][j]%=m;
        }
    return tmp;
}
int main()
{
    scanf("%d %d %d",&n,&K,&m);
    for(int i=0;i<n;++i)
        for(int j=0;j<n;++j)
            scanf("%d",&a[i][j]);
    Matrix b,c;
    for(int i=0;i<n;++i)
        for(int j=0;j<n;++j)
            c.num[i+n][j+n]=b.num[i][j+n]=a[i][j];
    for(int k=0;k<2;++k)
        for(int i=0;i<n;++i)
            c.num[i+k*n][i]=1;
    while(K)
    {
        if(K&1)
            b=b*c;
        K>>=1;
        c=c*c;
    }
    b.print();
    return 0;
}


效率更高的代码2:


#include<cstdio>
#include<cstring>
using namespace std;
int i,j,k,n,l,m,r;
bool s[32];
struct matrix
{
    int a[30][30];
    void pr()
    {
        for(i=0; i<n;printf("%d/n",a[i++][j]))
            for(j=0;j<n-1;++j)printf("%d ",a[i][j]);
    }
    matrix& operator+=(const matrix&x)
    {
        for(int i=0; i<n; ++i)
            for(int j=0; j<n; ++j)
            if(x.a[i][j])
            {
                a[i][j]+=x.a[i][j];
                if(a[i][j]>=m)a[i][j]%=m;
            }
        return *this;
    }
    matrix& operator*=(const matrix&x)
    {
        matrix t;
        int i,j,k;
        for(i=0; i<n; ++i)
            for(j=0; j<n; ++j)t.a[i][j]=0;
        for(i=0; i<n; ++i)
            for(k=0; k<n; ++k)
                if(a[i][k])
                    for(j=0; j<n; ++j)
                    {
                        t.a[i][j]+=a[i][k]*x.a[k][j];
                        if(t.a[i][j]>=m)t.a[i][j]%=m;
                    }
        return memcpy(a,t.a,sizeof(a)),*this;
    }
} t,a,unit,ans,exp;
int& fun(int &a)
{
    return a;
}
int main()
{
    for(scanf("%d%d%d",&n,&l,&m),i=0; i<30; ++i)unit.a[i][i]=1;
    for(i=0; i<n; ++i)
        for(j=0; j<n; ++j)
            scanf("%d",a.a[i]+j);
    for(r=-1;l;l>>=1)s[++r]=l&1;
    for(ans=exp=a; --r>=0; exp*=exp,s[r]?exp*=a:exp)
        t=exp,s[r]?ans*=(t*=a)+=unit,ans+=(t=exp)*=a:ans*=t+=unit;
    ans.pr();
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值