Matrix Power Series

给出矩阵A,求矩阵\(A+A^2+...+A^k\)各个元素\(mod\ yyb\)的值,\(n\leq 30,k\leq 10^9,yyb\leq 10^4\)。

法一:分治

显然是数列题,故数列最浅显的减法是分治,寻找其中重复计算的部分,故可以

\[A+A^2+...+A^{k/2}+A^{k/2+1}+...+A^k=
\]

\[A+A^2+...+A^{k/2}+A^{k/2}(A+...+A^{k/2})+(k\&1)A^k=
\]

\[(A^{k/2}+1)(A+...+A^{k/2})+(k\&1)A^k
\]

对式子主体进行分治,其他的部分快速幂即可。

参考代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#define il inline
#define ri register
using namespace std;
int n,yyb;
struct matrix{
int jz[30][30];
il void clear(){
memset(jz,0,sizeof(jz));
}
il void unit(){
clear();ri int i;
for(i=0;i<n;++i)jz[i][i]|=true;
}
il void read(){
ri int i,j;
for(i=0;i<n;++i)
for(j=0;j<n;++j)
scanf("%d",&jz[i][j]);
}
il void print(){
ri int i,j;
for(i=0;i<n;++i,putchar('\n'))
for(j=0;j<n;++j)
printf("%d ",jz[i][j]);
putchar('\n');
}
il matrix operator*(matrix x){
matrix y;y.clear();ri int i,j,k;
for(i=0;i<n;++i)
for(j=0;j<n;y.jz[i][j]%=yyb,++j)
for(k=0;k<n;++k)
y.jz[i][j]+=jz[i][k]*x.jz[k][j]%yyb;
return y;
}
il matrix operator+(matrix x){
matrix y;ri int i,j;
for(i=0;i<n;++i)
for(j=0;j<n;++j)
y.jz[i][j]=(jz[i][j]+x.jz[i][j])%yyb;
return y;
}template<class free>
il matrix operator^(free y){
matrix x(*this),ans;ans.unit();
while(y){
if(y&1)ans=ans*x;
x=x*x,y>>=1;
}return ans;
}
}state,unit,zero;
il matrix efen(int);
int main(){
int k,i;
scanf("%d%d%d",&n,&k,&yyb);
unit.unit(),state.read();
efen(k).print();
return 0;
}
il matrix efen(int y){
if(!y)return unit;
if(y==1)return state;
return ((state^(y>>1))+unit)*efen(y>>1)
+((y&1)?(state^y):zero);
}

法二:矩阵快速幂

显然数列的题目,经常会存在递推方程,于是矩阵快速幂会在其中大有用武之地,于是设\(f_i=A+A^2+...+A^i\),不难有递推方程\(f_i=f_{i-1}+A^i\),于是我们可以同时转移\(f_i,A^i\),故状态矩阵为

\[\begin{bmatrix}A_i&f_{i-1}\end{bmatrix}
\]

转移矩阵为

\[\begin{bmatrix}A&I\\0&I\end{bmatrix}
\]

以此矩阵中套矩阵仿照套路即可。

参考代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#define il inline
#define ri register
using namespace std;
int n,yyb;
struct matrix1{
int jz[30][30];
il void read(){
ri int i,j;
for(i=0;i<n;++i)
for(j=0;j<n;++j)
scanf("%d",&jz[i][j]);
}
il void print(){
ri int i,j;
for(i=0;i<n;++i,putchar('\n'))
for(j=0;j<n;++j)
printf("%d ",jz[i][j]);
putchar('\n');
}
il void clear(){
memset(jz,0,sizeof(jz));
}
il void unit(){
clear();ri int i;
for(i=0;i<n;++i)jz[i][i]|=true;
}
il matrix1 operator*(matrix1 x){
matrix1 y;y.clear();
ri int i,j,k;
for(i=0;i<n;++i)
for(j=0;j<n;y.jz[i][j]%=yyb,++j)
for(k=0;k<n;++k)
y.jz[i][j]+=jz[i][k]*x.jz[k][j]%yyb;
return y;
}
il matrix1 operator+(matrix1 x){
matrix1 y;ri int i,j;
for(i=0;i<n;++i)
for(j=0;j<n;++j)
y.jz[i][j]=(jz[i][j]+x.jz[i][j])%yyb;
return y;
}template<class free>
il matrix1 operator^(free y){
matrix1 ans,x(*this);ans.unit();
while(y){
if(y&1)ans=ans*x;
x=x*x,y>>=1;
}return ans;
}
}A;
struct matrix2{
matrix1 jz[2][2];
il void clear(){
memset(jz,0,sizeof(jz));
}
il void unit(){
clear();ri int i;
for(i=0;i<2;++i)jz[i][i].unit();
}
il matrix2 operator*(matrix2 x){
matrix2 y;y.clear();
ri int i,j,k;
for(i=0;i<2;++i)
for(j=0;j<2;++j)
for(k=0;k<2;++k)
y.jz[i][j]=y.jz[i][j]+jz[i][k]*x.jz[k][j];
return y;
}template<class free>
il matrix2 operator^(free y){
matrix2 ans,x(*this);ans.unit();
while(y){
if(y&1)ans=ans*x;
x=x*x,y>>=1;
}return ans;
}
}state,tran;
int main(){
int k;
scanf("%d%d%d",&n,&k,&yyb);
A.read(),state.jz[0][0]=A;
tran.jz[0][0]=A,tran.jz[0][1].unit();
tran.jz[1][1].unit(),state=state*(tran^k);
state.jz[0][1].print();
return 0;
}

法三:倍增前缀和优化

数列求和可以利用倍增优化,主要思想是维护\(A^{2^i}\),这个显然可通过\(A^{2^{i+1}}=(A^{2^i})^2\)来暴力递推,再维护一个倍增的数列,\(f_i=A^1+A^2+...+A^{2^i}\),不难得知其转移方程为\(f_i=f_{i-1}A^{2^{i-1}}+f_{i-1}\),而这个的维护也可以暴力维护,于是对于我们的求和,以\(A+A^2+...+A^{15}\)为例,有

\[A+A^2+...+A^{15}=f_3+A^9+...+A^{15}=
\]

\[f_3+A^8(A+...+A^7)=f_3+A^8(f_2+A^5+A^6+A^7)=
\]

\[f_3+A^8[f_2+A^4(A+A^2+A^3)]=
\]

\[f_3+A^8[f_2+A^4(f_1+A^2A^1)]=f_3+A^8[f_2+A^4(f_1+A^2f_0)]
\]

于是按照这个先维护好一段倍增前缀和,再对后式提公因式,继续利用倍增前缀和优化,不停地继续,即可得到答案,当然你也可以递归处理,以下参考程序用的是非递归的方式。

参考代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#define il inline
#define ri register
using namespace std;
int n,yyb;
struct matrix{
int jz[30][30];
il void clear(){
memset(jz,0,sizeof(jz));
}
il void unit(){
clear();ri int i;
for(i=0;i<n;++i)jz[i][i]|=true;
}
il void read(){
ri int i,j;
for(i=0;i<n;++i)
for(j=0;j<n;++j)
scanf("%d",&jz[i][j]);
}
il void print(){
ri int i,j;
for(i=0;i<n;putchar('\n'),++i)
for(j=0;j<n;++j)
printf("%d ",jz[i][j]);
putchar('\n');
}
il matrix operator*(matrix x){
matrix y;ri int i,j,k;y.clear();
for(i=0;i<n;++i)
for(j=0;j<n;y.jz[i][j]%=yyb,++j)
for(k=0;k<n;++k)
y.jz[i][j]+=jz[i][k]*x.jz[k][j]%yyb;
return y;
}
il matrix operator+(matrix x){
matrix y;ri int i,j;
for(i=0;i<n;++i)
for(j=0;j<n;++j)
y.jz[i][j]=(jz[i][j]+x.jz[i][j])%yyb;
return y;
}
}A,p[31],sum[31],ans,jilu;
int main(){
int k,i;
scanf("%d%d%d",&n,&k,&yyb);
A.read(),p[0]=A,jilu.unit(),sum[0]=A;
for(i=1;i<=30;++i)p[i]=p[i-1]*p[i-1];
for(i=1;i<=30;++i)sum[i]=sum[i-1]*p[i-1]+sum[i-1];
for(i=30;i>=0;--i)
if(k>>i&1){
ans=ans+sum[i]*jilu;
jilu=jilu*p[i];
}ans.print();
return 0;
}

总上所诉,不难得知数列题目的一般求法,矩阵快速幂和分治,而特殊地对于数列前缀和的问题,我们可以利用倍增前缀和优化,但无论如何,数列问题绝不只一条道路通往罗马。

Matrix Power Series的更多相关文章

  1. 线性代数(矩阵乘法):POJ 3233 Matrix Power Series

    Matrix Power Series   Description Given a n × n matrix A and a positive integer k, find the sum S = ...

  2. C++题解:Matrix Power Series ——矩阵套矩阵的矩阵加速

    Matrix Power Series r时间限制: 1 Sec 内存限制: 512 MB 题目描述 给定矩阵A,求矩阵S=A^1+A^2+--+A^k,输出矩阵,S矩阵中每个元都要模m. 数据范围: ...

  3. POJ 3233 Matrix Power Series(二分等比求和)

    Matrix Power Series [题目链接]Matrix Power Series [题目类型]二分等比求和 &题解: 这题我原来用vector写的,总是超时,不知道为什么,之后就改用 ...

  4. POJ 3233 Matrix Power Series (矩阵乘法)

    Matrix Power Series Time Limit: 3000MS   Memory Limit: 131072K Total Submissions: 11954   Accepted:  ...

  5. 构造矩阵解决这个问题 【nyoj299 Matrix Power Series】

    矩阵的又一个新使用方法,构造矩阵进行高速幂. 比方拿 nyoj299 Matrix Power Series 来说 给出这样一个递推式: S = A + A2 + A3 + - + Ak. 让你求s. ...

  6. POJ 3233 Matrix Power Series(矩阵快速幂)

    Matrix Power Series Time Limit: 3000MS Memory Limit: 131072K Total Submissions: 19338 Accepted: 8161 ...

  7. POJ 3233 Matrix Power Series 【经典矩阵快速幂+二分】

    任意门:http://poj.org/problem?id=3233 Matrix Power Series Time Limit: 3000MS   Memory Limit: 131072K To ...

  8. [ACM] POJ 3233 Matrix Power Series (求矩阵A+A^2+A^3...+A^k,二分求和或者矩阵转化)

    Matrix Power Series Time Limit: 3000MS   Memory Limit: 131072K Total Submissions: 15417   Accepted:  ...

  9. poj 3233 Matrix Power Series(矩阵二分,高速幂)

    Matrix Power Series Time Limit: 3000MS   Memory Limit: 131072K Total Submissions: 15739   Accepted:  ...

  10. [POJ3233]Matrix Power Series 分治+矩阵

    本文为博主原创文章,欢迎转载,请注明出处 www.cnblogs.com/yangyaojia [POJ3233]Matrix Power Series 分治+矩阵 题目大意 A为n×n(n<= ...

随机推荐

  1. CodeForces-1234C-Pipes-dfs

    You are given a system of pipes. It consists of two rows, each row consists of nn pipes. The top lef ...

  2. 第37讲 谈谈Spring Bean的生命周期和作用域

    在企业应用软件开发中,Java 是毫无争议的主流语言,开放的 Java EE 规范和强大的开源框架功不可没,其中 Spring 毫无疑问已经成为企业软件开发的事实标准之一.今天这一讲,我将补充 Spr ...

  3. 两个问题: 1、头文件重复包含 2、头文件加了ifndef条件预处理指令为什么还会定义

    第一个问题:编译时重定义 文件1.h void fun1(); struct A { int a char b; };   文件2.h #include"1.h" struct B ...

  4. C#Object与XML文件或二进制文件之间的转化

    Object To Xml 文件 public static bool Serializer<T>(object obj, string path) { FileStream xmlfil ...

  5. Zookeeper怎么实现分布式锁?

    对访问资源 R1 的过程加锁,在操作 O1 结束对资源 R1 访问前,其他操作不允许访问资源 R1.以上算是对独占锁的简单定义了,那么这段定义在 Zookeeper 的"类 Unix/Lin ...

  6. Maven精选系列--classifier元素妙用

    首先来看这么一个依赖 <dependency> <groupId>net.sf.json-lib</groupId> <artifactId>json- ...

  7. sql实现取汉字大写首字母

    )) ) AS BEGIN DECLARE @py TABLE( ch ), hz1 ) COLLATE Chinese_PRC_CS_AS_KS_WS, hz2 ) COLLATE Chinese_ ...

  8. pycharm快捷键表

    快捷键 作用 ctrl(command)+c 复制 ctrl+v 粘贴 ctrl+z 撤销 ctrl+x 剪切,默认整行 ctrl+a 全选 ctrl+f 查找:选中批量修改 shift+ctrl+z ...

  9. Fedora25安装mariadb并设置权限

    MariaDB版本10.1.21 Fedora版本25 1.Change root user sudo -i 2. dnf install -y mysql dnf install -y mariad ...

  10. myeclipe 中配置maven

    1.配置maven 2. 2