题目:POJ3233.
题目大意:给定
k
k
k和一个
n
∗
n
n*n
n∗n的矩阵
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
1≤k≤109,1≤n≤30.
一开始想到的是直接用等比数列求和公式,一看好像不会矩阵求逆…
然后想到 ∑ 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=Al−1∑i=1r−l+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
2∣n时,直接计算出
[
⌊
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=lans∗A2n.
2.否则,计算出
[
⌊
n
2
⌋
,
n
−
1
]
[\left\lfloor\frac{n}{2}\right\rfloor,n-1]
[⌊2n⌋,n−1]的答案为
r
a
n
s
=
l
a
n
s
∗
A
⌊
n
2
⌋
rans=lans*A^{\left\lfloor\frac{n}{2}\right\rfloor}
rans=lans∗A⌊2n⌋,然后再加上一个
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;
}