题面



$ solution: $

首先,如果题目只要我们求 $ A^K $ 那这一题我们可以直接模版矩乘快速幂来做,但是它现在让我们求 $ \sum_{i=1}{k}{(Ai)} $ 所以我们思考一下这两者是否有什么关系。仔细一想,不难发现几个东西:

  1. 一次矩阵乘法复杂度为 $ O(n^3) $ ,所以我们不能进行太多次矩阵乘法
  2. 快速幂的复杂度为 $ O(logk) $ 再乘一下矩阵乘法的复杂度,我们现在只能再接受 $ O(log) $ 级别的处理了
  3. 矩阵乘法满足交换律和结合律!!!!
  4. 若我们已经知道了 $ A1+A2+A3+A4 $ 的值,我们 需要 $ A5+A6+A7+A8 $ 的值,我们可以直接将前者乘上一个 $ A^4 $ 就可以了!

根据以上发现,我们不妨再设一个矩阵B,来帮助我们理解!

我们设 $ B_x=A1+A2+.....+A^x $ 根据上面第四个的原理我们可以得到:

  1. $ B_1=A^1 $
  2. $ B_2=A1+A1\times A^1=B_1+B_1\times A^1 $
  3. $ B_4=(A1+A2)+A^2\times (A1+A2)=B_2+A^2\times B_2 $
  4. $ B_8=(A1+A2+A3+A4)+A^4\times (A1+A2+A3+A4)=B_4+A^4\times B_4 $
  5. $ B_{16}=B_8+A^8\times B_8 $
  6. $ B_{2\times x}==B_x+A_x\times B_x $
  7. 在根据上面第四个规律可以得出: $ B_{x\times y}==B_x+A_x\times B_y $

而我们要得到的最终结果就是 $ B_K $ 嘛。如果上述的B矩阵的底数能相加,那我们不就可以仿照二进制来得到 $ B_K $ 了吗?就像K等于19,如果我们可以直接 $ B_{19}=B_{1+2+16}=B_1+B_2+B_{16} $ (假设!)那我们就能log预处理所有 $ B_{1<<i} $ 然后log求出 $ B_K $ 了!

我们再思考一下,发现上述 $ B $ 矩阵的底数是可以相加的,但是不像上面那个式子那么直接相加,我们应该这么求: $ B_{x+y}=B_x+A^x\times B_y $ 这样底数就可以相加了!!!

然后我们再仿照二进制,就能log求出 $ B_K $ 了!



$ code: $

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set> #define ll long long
#define db double
#define inf 0x7fffffff
#define rg register int using namespace std; int n,m,k; inline int qr(){ char ch;//快读
while((ch=getchar())<'0'||ch>'9');
int res=ch^48;
while((ch=getchar())>='0'&&ch<='9')
res=res*10+(ch^48);
return res;
} struct su{
int s[30][30];
inline void read(){//读入一个矩阵
for(rg i=0;i<n;++i)
for(rg j=0;j<n;++j)
s[i][j]=qr();
}
inline void write(){//输出一个矩阵
for(rg i=0;i<n;++i){
for(rg j=0;j<n;++j)
printf("%d ",s[i][j]);
puts("");
}
}
inline su operator *(su x){//矩阵乘法
su y; memset(y.s,0,sizeof(y.s));
for(rg i=0;i<n;++i)
for(rg j=0;j<n;++j)
for(rg o=0;o<n;++o)
y.s[i][j]+=(ll)s[i][o]*x.s[o][j]%m,y.s[i][j]%=m;
return y;
}
inline su operator +(su x){//矩阵加法
for(rg i=0;i<n;++i)
for(rg j=0;j<n;++j)
x.s[i][j]+=s[i][j],x.s[i][j]%=m;
return x;
}
}ans,a[33],b[33]; int main(){
//freopen("t1.in","r",stdin);
//freopen("t1.out","w",stdout);
n=qr();k=qr();m=qr();
a[1].read(); b[1]=a[1];
for(rg i=1;i<32;++i){//我们求出对应所有的a与b
a[i+1]=a[i]*a[i]; //a数组表示A[1<<i-1]
b[i+1]=b[i]*a[i]+b[i]; //b数组表示b[1<<i-1]
}
for(rg i=1;i<=32;++i){//根据二进制,不断累加,一直到b[k]
if(k&1)ans=ans*a[i]+b[i]; //ans相当于b[ans]
k>>=1; //k&1表示这一位上是一,不懂可以先学下快速幂的原理
} ans.write();//累加完毕输出
return 0;
}

我们发现上面main函数中的两个for循环可以换成一个,于是:

int main(){
n=qr();k=qr();m=qr(); a.read(); b=a;
while(k){
if(k&1)ans=ans*a+b;
b=b*a+b; a=a*a; k>>=1;
} ans.write(); //不仅代码短,跑的还十分快!!!!!
return 0;
}

POJ3233 Matrix Power Series(快速幂求等比矩阵和)的更多相关文章

  1. POJ 3233 Matrix Power Series——快速幂&&等比&&分治

    题目 给定一个 $n \times n$  的矩阵 $A$ 和正整数 $k$ 和 $m$.求矩阵 $A$ 的幂的和. $$S = A + A^2 + ... + A^k$$ 输出 $S$ 的各个元素对 ...

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

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

  3. POJ3233:Matrix Power Series(矩阵快速幂+二分)

    http://poj.org/problem?id=3233 题目大意:给定矩阵A,求A + A^2 + A^3 + … + A^k的结果(两个矩阵相加就是对应位置分别相加).输出的数据mod m.k ...

  4. POJ3233 Matrix Power Series 矩阵快速幂 矩阵中的矩阵

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

  5. POJ3233]Matrix Power Series && [HDU1588]Gauss Fibonacci

    题目:Matrix Power Series 传送门:http://poj.org/problem?id=3233 分析: 方法一:引用Matrix67大佬的矩阵十题:这道题两次二分,相当经典.首先我 ...

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

    题目要求的是 A+A2+...+Ak,而不是单个矩阵的幂. 那么可以构造一个分块的辅助矩阵 S,其中 A 为原矩阵,E 为单位矩阵,O 为0矩阵    将 S 取幂,会发现一个特性: Sk +1右上角 ...

  7. POJ3233 Matrix Power Series

    Description Given a n × n matrix A and a positive integer k, find the sum S = A + A2 + A3 + … + Ak. ...

  8. poj3233—Matrix Power Series

    题目链接:http://poj.org/problem?id=3233 题目意思:给一个矩阵n*n的矩阵A和一个k,求一个式子 S = A + A2 + A3 + … + Ak. 这个需要用到等比数列 ...

  9. POJ-3233 Matrix Power Series 矩阵A^1+A^2+A^3...求和转化

    S(k)=A^1+A^2...+A^k. 保利求解就超时了,我们考虑一下当k为偶数的情况,A^1+A^2+A^3+A^4...+A^k,取其中前一半A^1+A^2...A^k/2,后一半提取公共矩阵A ...

随机推荐

  1. 两个序列求前k大和

    ---恢复内容开始--- 没有题目,没有题意,这是学长提过的一个技巧,给你两个排好序的序列,每次可以各从中取一个,求前k大的和, 一个优先队列,先将a序列中最大的那个和b序列所有元素相加存进队列中,每 ...

  2. BZOJ2144跳跳棋——LCA+二分

    题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的 游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动 ...

  3. HDU-2087-KMP-水题

    纯KMP #include <cstdio> #include <algorithm> #include <cstring> #include <ctype. ...

  4. python 解释器交互模块 -- sys

    sys模块是与python解释器交互的一个接口 sys.argv 命令行参数List,第一个元素是程序本身路径 sys.getdefaultencoding(): 获取系统当前编码,一般默认为asci ...

  5. 2015 HIAST Collegiate Programming Contest H

    A sequence of positive and non-zero integers called palindromic if it can be read the same forward a ...

  6. MT【42】抛物线不常见性质1.

    评:特别的,当$PP'$为切线时,$\angle PSK=90^0$ 注:S为抛物线焦点.

  7. 洛谷P4332 [SHOI2014]三叉神经树(LCT,树剖,二分查找,拓扑排序)

    洛谷题目传送门 你谷无题解于是来补一发 随便百度题解,发现了不少诸如树剖\(log^3\)LCT\(log^2\)的可怕描述...... 于是来想想怎么利用题目的性质,把复杂度降下来. 首先,每个点的 ...

  8. Leetcode 28.实现strStr() By Python

    实现 strStr() 函数. 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始).如果不存在,则返 ...

  9. 自学Linux Shell15.1-处理信号

    点击返回 自学Linux命令行与Shell脚本之路 15.1-处理信号 Linux使用信号与系统上运行的进程进行通信.可以使用这些信号控制Shell脚本的运行,只需要让shell脚本在接收到来自Lin ...

  10. 自学Zabbix3.12-动作Action

    点击返回:自学Zabbix之路 点击返回:自学Zabbix4.0之路 点击返回:自学zabbix集锦 自学Zabbix3.12-动作Action介绍 1. 动作action 在配置好监控项和触发器之后 ...