蓝书(算法竞赛进阶指南)刷题记录——POJ3233 Matrix Power Series(分治+矩阵乘法)

题目:POJ3233.
题目大意:给定 k k k和一个 n ∗ n n*n nn的矩阵 A A A,求 ∑ i = 1 k A i \sum_{i=1}^{k}A^i i=1kAi.
1 ≤ k ≤ 1 0 9 , 1 ≤ n ≤ 30 1\leq k\leq 10^9,1\leq n\leq 30 1k109,1n30.

一开始想到的是直接用等比数列求和公式,一看好像不会矩阵求逆…

然后想到 ∑ i = l r A i = A l − 1 ∑ i = 1 r − l + 1 A i \sum_{i=l}^{r}A^i=A^{l-1}\sum_{i=1}^{r-l+1}A^{i} i=lrAi=Al1i=1rl+1Ai,顿时有了思路.

考虑分治解决这个问题,开始处理区间 [ 1 , n ] [1,n] [1,n]的时候考虑处理出 l a n s = [ 1 , ⌊ n 2 ⌋ ] lans=[1,\left\lfloor\frac{n}{2}\right\rfloor] lans=[1,2n]的答案,然后分情况讨论:
1.当 2 ∣ n 2|n 2n时,直接计算出 [ ⌊ n 2 ⌋ , n ] [\left\lfloor\frac{n}{2}\right\rfloor,n] [2n,n]的答案为 r a n s = l a n s ∗ A n 2 rans=lans*A^{\frac{n}{2}} rans=lansA2n.
2.否则,计算出 [ ⌊ n 2 ⌋ , n − 1 ] [\left\lfloor\frac{n}{2}\right\rfloor,n-1] [2n,n1]的答案为 r a n s = l a n s ∗ A ⌊ n 2 ⌋ rans=lans*A^{\left\lfloor\frac{n}{2}\right\rfloor} rans=lansA2n,然后再加上一个 A n A^n An即可.

考虑到矩阵的幂可以用快速幂直接求出,那么我们就可以做到 O ( log ⁡ k ) O(\log k) O(logk)次递归,递归到每一层都只用 O ( log ⁡ k ) O(\log k) O(logk)的时间计算,总复杂度 O ( n 3 log ⁡ 2 k ) O(n^3\log^2 k) O(n3log2k).

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
  using namespace std;

#define Abigail inline void
typedef long long LL;

const int N=30;

int n,k,mod;
struct matrix{
  int n,m,v[N+9][N+9];
  
  matrix operator + (const matrix &p)const{
  	matrix tmp=matrix();
  	tmp.n=n;tmp.m=m;
	for (int i=1;i<=n;++i)
	  for (int j=1;j<=m;++j)      //手残把j写成了i
	    tmp.v[i][j]=(v[i][j]+p.v[i][j])%mod;
	return tmp;
  }
  
  matrix operator * (const matrix &p)const{
    matrix tmp=matrix();      //然后没有初始化...
    tmp.n=n;tmp.m=p.m;
    for (int i=1;i<=tmp.n;++i)
      for (int k=1;k<=m;++k)
        for (int j=1;j<=tmp.m;++j)
          tmp.v[i][j]=(tmp.v[i][j]+v[i][k]*p.v[k][j])%mod;
    return tmp;
  }
  
}a;

matrix e(int n){
  matrix e=matrix();
  for (int i=1;i<=n;++i)
    e.v[i][i]=1;
  e.n=e.m=n;
  return e;
}

matrix power(matrix a,int k){
  matrix s=e(a.n);
  for (;k;k>>=1,a=a*a)
    if (k&1) s=s*a;
  return s;
}

matrix Calc(matrix a,int k){
  if (k==1) return a;
  matrix ans=Calc(a,k>>1);
  ans=ans+power(a,k>>1)*ans;
  if (k&1) ans=ans+power(a,k);
  return ans; 
}

Abigail into(){
  scanf("%d%d%d",&n,&k,&mod);
  a.n=a.m=n;
  for (int i=1;i<=n;++i)
    for (int j=1;j<=n;++j){
      scanf("%d",&a.v[i][j]);
      a.v[i][j]%=mod;
	}
}

Abigail work(){
  a=Calc(a,k);
}

Abigail outo(){
  for (int i=1;i<=n;++i){
  	for (int j=1;j<n;++j)
  	  printf("%d ",a.v[i][j]);
  	printf("%d\n",a.v[i][n]);
  }
}

int main(){
  into();
  work();
  outo();
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值