题目:Matrix Power Series

传送门:http://poj.org/problem?id=3233

分析:

方法一:引用Matrix67大佬的矩阵十题:这道题两次二分,相当经典。首先我们知道,A^i可以二分求出。然后我们需要对整个题目的数据规模k进行二分。比如,当k=6时,有:$ S(6)= A + A^2 + A^3 + A^4 + A^5 + A^6 =\underline{(A + A^2 + A^3)} + A^3*\underline{(A + A^2 + A^3)}。   $

即对于k:如果k是偶数,就二分减小规模,$ S(k)=S(\frac{k}{2})+A^{\frac{n}{2}} *S(\frac{k}{2}) $。如果k是奇数,那么 $ S(k)=S(k-1)+A^n $; 其中 $ A^n $使用矩阵快速幂可以快速计算。

 #include <iostream>
#include <cstdio>
using namespace std;
const int maxN=;
int MOD;
struct Matrix{int n,a[maxN][maxN];}A,E;
Matrix operator+(Matrix A,Matrix B){
Matrix RT{};RT.n=A.n;
for(int i=;i<RT.n;++i)
for(int j=;j<RT.n;++j)
RT.a[i][j]=(A.a[i][j]+B.a[i][j])%MOD;
return RT;
}
Matrix operator*(Matrix A,Matrix B){
Matrix RT{};RT.n=A.n;
for(int i=;i<A.n;++i)
for(int j=;j<A.n;++j)
for(int k=;k<A.n;++k)
(RT.a[i][j]+=A.a[i][k]*B.a[k][j])%=MOD;
return RT;
}
Matrix operator^(Matrix A,int n){
Matrix RT=E;
for(;n;n>>=){
if(n&)RT=RT*A;
A=A*A;
}
return RT;
}
Matrix Sum(Matrix &A,int n){
if(n==)return A;
if(n&)return (A^n) + Sum(A,n-);
Matrix B=Sum(A,n>>);
return B+((A^(n>>))*B);
}
int main(){
for(int n,k;~scanf("%d %d %d",&n,&k,&MOD);){
A.n=E.n=n;
for(int i=;i<n;++i)
for(int j=;j<n;++j){
scanf("%d",&A.a[i][j]);
A.a[i][j]%=MOD;E.a[i][j]=;
}
for(int i=;i<n;++i)E.a[i][i]=;
Matrix RT=Sum(A,k);
for(int i=;i<n;++i){
for(int j=;j<n;++j)
printf("%d ",RT.a[i][j]);
puts("");
}
}
return ;
}

方法二:对于多项式,有秦九韶算法,而对$ A + A^2 + A^3 + … + A^k $ 这样的多项式,可以二进制优化秦九韶算法。$ S( 2^i ) $ 是可以快速计算的: $S( 2^i ) = S( 2^{(i-1)} ) * (E + A^{(2^i)} )$。记:$A[i]=A^{2^i}$、$S[i]=S(2^i)$;预处理A[i]、s[i]。

比如k=6时:$ S(6)=\underline{(A + A^2 + A^3 + A^ 4)} * A^2 + \underline{(A + A^2 )} = S(4) * A(2) + S(2) = S[2]*A[1]+S[1] $

 #include <iostream>
#include <cstdio>
using namespace std;
const int maxN=;
int MOD;
struct Matrix{int n,a[maxN][maxN];}A[],B[];
Matrix operator+(Matrix A,Matrix B){
Matrix RT{};RT.n=A.n;
for(int i=;i<RT.n;++i)
for(int j=;j<RT.n;++j)
RT.a[i][j]=(A.a[i][j]+B.a[i][j])%MOD;
return RT;
}
Matrix operator*(Matrix A,Matrix B){
Matrix RT{};RT.n=A.n;
for(int i=;i<A.n;++i)
for(int j=;j<A.n;++j)
for(int k=;k<A.n;++k)
(RT.a[i][j]+=A.a[i][k]*B.a[k][j])%=MOD;
return RT;
}
int main(){
Matrix E{};
for(int n,k;~scanf("%d %d %d",&n,&k,&MOD);){
A[].n=E.n=n;
for(int i=;i<n;++i)
for(int j=;j<n;++j){
scanf("%d",&A[].a[i][j]);
A[].a[i][j]%=MOD;E.a[i][j]=;
}
for(int i=;i<n;++i)E.a[i][i]=;
for(int i=;k>>i;++i)A[i]=A[i-]*A[i-];
B[]=A[];
for(int i=;k>>i;++i)B[i]=B[i-]*(A[i-]+E);
Matrix RT{};RT.n=n;
for(int i=;~i;--i)if(k>>i&)RT=RT*A[i]+B[i];
for(int i=;i<n;++i){
for(int j=;j<n;++j)
printf("%d ",RT.a[i][j]);
puts("");
}
}
return ;
}

优化一下常数(141s -> 32s):

 #include <iostream>
#include <cstdio>
using namespace std;
const int maxN=;
int MOD;
struct Matrix{int n,a[maxN][maxN];}A[],B[];
Matrix operator+(Matrix A,Matrix B){
Matrix RT{};RT.n=A.n;
for(int i=;i<RT.n;++i)
for(int j=;j<RT.n;++j){
RT.a[i][j]=A.a[i][j]+B.a[i][j];
if(RT.a[i][j]>=MOD)RT.a[i][j]-=MOD;
}
return RT;
}
Matrix operator*(Matrix A,Matrix B){
Matrix RT{};RT.n=A.n;
for(int i=;i<A.n;++i)
for(int j=;j<A.n;++j){
for(int k=;k<A.n;++k)
RT.a[i][j]+=A.a[i][k]*B.a[k][j];
RT.a[i][j]%=MOD;
}
return RT;
}
int main(){
Matrix E{};
for(int n,k;~scanf("%d %d %d",&n,&k,&MOD);){
A[].n=E.n=n;
for(int i=;i<n;++i)
for(int j=;j<n;++j){
scanf("%d",&A[].a[i][j]);
A[].a[i][j]%=MOD;E.a[i][j]=;
}
for(int i=;i<n;++i)E.a[i][i]=;
for(int i=;k>>i;++i)A[i]=A[i-]*A[i-];
B[]=A[];
for(int i=;k>>i;++i)B[i]=B[i-]*(A[i-]+E);
Matrix RT{};RT.n=n;
for(int i=;~i;--i)if(k>>i&)RT=RT*A[i]+B[i];
for(int i=;i<n;++i){
for(int j=;j<n;++j)
printf("%d ",RT.a[i][j]);
puts("");
}
}
return ;
}

方法三:有种很有意思的打法:构造矩阵

$ T = \left[ \begin{array}{cc} E & 0 \\ A & A \end{array}  \right]$ 、 $ T^2 =  \left[ \begin{array}{cc} E & 0 \\ {A + A^2}  & A^2 \end{array}  \right]$ 、 $ T^2 =  \left[ \begin{array}{cc} E & 0 \\ {A + A^2 + A^3}  & A^3 \end{array} \right]$ 、

这个矩阵的左下角就是矩阵次方和。$ T^n =  \left[ \begin{array}{cc} E & 0 \\ {A + A^2 + .. A^n}  & A^n \end{array} \right]$

这个矩阵可以直接快速幂求。

把RT矩阵设为 $ RT =  \left[ \begin{array}{cc} 0 & E \\ 0  & 0 \end{array} \right] $,然后 $ RT \times T^n =   \left[ \begin{array}{cc} {A + A^2 + .. A^n} & 0 \\ 0  & 0 \end{array} \right] $

 #include <iostream>
#include <cstdio>
using namespace std;
const int maxN=;
int MOD;
struct Matrix{int n,a[maxN][maxN];}A;
Matrix operator+(Matrix A,Matrix B){
Matrix RT{};RT.n=A.n;
for(int i=;i<RT.n;++i)
for(int j=;j<RT.n;++j){
RT.a[i][j]=A.a[i][j]+B.a[i][j];
if(RT.a[i][j]>=MOD)RT.a[i][j]-=MOD;
}
return RT;
}
Matrix operator*(Matrix A,Matrix B){
Matrix RT{};RT.n=A.n;
for(int i=;i<A.n;++i)
for(int j=;j<A.n;++j){
for(int k=;k<A.n;++k)
RT.a[i][j]+=A.a[i][k]*B.a[k][j];
RT.a[i][j]%=MOD;
}
return RT;
}
Matrix Sum(Matrix A,int k){
Matrix RT{};int n=RT.n=A.n;
for(int t=n/,i=;i<n;++i)RT.a[i][i+t]=;
for(;k;k>>=){
if(k&)RT=RT*A;
A=A*A;
}
return RT;
}
int main(){
for(int n,k;~scanf("%d %d %d",&n,&k,&MOD);){
A.n=n<<;
for(int i=;i<n;++i){
A.a[i][i]=;
for(int j=,t;j<n;++j){
scanf("%d",&t);if(t>=MOD)t%=MOD;
A.a[i+n][j]=A.a[i+n][j+n]=t;
}
}
Matrix RT=Sum(A,k);
for(int i=;i<n;++i){
for(int j=;j<n;++j)
printf("%d ",RT.a[i][j]);
puts("");
}
}
return ;
}

题目: Gauss Fibonacci

链接:http://acm.hdu.edu.cn/showproblem.php?pid=1588

分析:Fibonacci数列可用矩阵:$ Fib =  \left[ \begin{array}{cc} 0 & 1 \\ 1  & 1 \end{array} \right] $ 表示,f(i)=$Fib^n$的左下角元素的值。

然后即求 $ Fib^b + Fib^{k+b} + Fib^{2*k+b} + ... Fib^{(n-1)*k+b} $

即:$ Fib^b * (E + Fib^k + Fib^{2*k} + Fib^{3*k} + ... +Fib^{(n-1)*k} $ = $ Fib^b * (E + (Fib^k) + {(Fib^k)}^2 + {(Fib^k)}^3 + ... +{(Fib^k)}^{(n-1)} )$

令  $ A=Fib^k $;

则求: $ Fib^b * (E + A + A^2 + A^3 +.. A^n) $

就和上面一样了。

 #include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
const int maxN=;
LL MOD;
struct Matrix{LL a[maxN][maxN];}A[],B[],E,Fib;
Matrix operator+(Matrix A,Matrix B){
Matrix RT{};
for(int i=;i<;++i)
for(int j=;j<;++j){
RT.a[i][j]=A.a[i][j]+B.a[i][j];
if(RT.a[i][j]>=MOD)RT.a[i][j]-=MOD;
}
return RT;
}
Matrix operator*(Matrix A,Matrix B){
Matrix RT{};
for(int i=;i<;++i)
for(int j=;j<;++j){
for(int k=;k<;++k)
RT.a[i][j]+=A.a[i][k]*B.a[k][j];
RT.a[i][j]%=MOD;
}
return RT;
}
Matrix operator^(Matrix A,LL n){
Matrix RT=E;
for(;n;n>>=){
if(n&)RT=RT*A;
A=A*A;
}
return RT;
}
int main(){
for(LL k,b,n;~scanf("%lld %lld %lld %lld",&k,&b,&n,&MOD);){
--n;
Fib.a[][]=;Fib.a[][]=;
Fib.a[][]=;Fib.a[][]=;
E.a[][]=E.a[][]=;
E.a[][]=E.a[][]=; A[]=Fib^k;
for(int i=;n>>i;++i)A[i]=A[i-]*A[i-];
B[]=A[];
for(int i=;n>>i;++i)B[i]=B[i-]*(A[i-]+E); Matrix RT{};
for(int i=;~i;--i)if(n>>i&)RT=RT*A[i]+B[i];
RT=(RT+E)*(Fib^b);
printf("%lld\n",RT.a[][]);
}
return ;
}
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
const int maxN=;
LL MOD;
struct Matrix{int n;LL a[maxN][maxN];}A,Fib;
Matrix operator+(Matrix A,Matrix B){
Matrix RT{};
for(int i=;i<;++i)
for(int j=;j<;++j){
RT.a[i][j]=A.a[i][j]+B.a[i][j];
if(RT.a[i][j]>=MOD)RT.a[i][j]-=MOD;
}
return RT;
}
Matrix operator*(Matrix A,Matrix B){
Matrix RT{};int n=RT.n=A.n;
for(int i=;i<n;++i)
for(int j=;j<n;++j){
for(int k=;k<n;++k)
RT.a[i][j]+=A.a[i][k]*B.a[k][j];
RT.a[i][j]%=MOD;
}
return RT;
}
Matrix operator^(Matrix A,LL n){
Matrix RT;
RT.n=A.n;
for(int i=;i<RT.n;++i)for(int j=;j<RT.n;++j)RT.a[i][j]=;
for(int i=;i<RT.n;++i)RT.a[i][i]=;
for(;n;n>>=){
if(n&)RT=RT*A;
A=A*A;
}
return RT;
}
int main(){
for(LL k,b,n;~scanf("%lld %lld %lld %lld",&k,&b,&n,&MOD);){
--n;
Fib.n=;
Fib.a[][]=;Fib.a[][]=;
Fib.a[][]=;Fib.a[][]=; A=Fib^k;
A.n=;
A.a[][]=A.a[][]=A.a[][];
A.a[][]=A.a[][]=A.a[][];
A.a[][]=A.a[][]=A.a[][];
A.a[][]=A.a[][]=A.a[][];
A.a[][]=;A.a[][]=;
A.a[][]=;A.a[][]=; A=A^n;
A.n=;
A.a[][]=A.a[][]+;A.a[][]=A.a[][]+;
A.a[][]=A.a[][]+;A.a[][]=A.a[][]+; A=(Fib^b)*A;
printf("%lld\n",A.a[][]);
}
return ;
}

POJ3233]Matrix Power Series && [HDU1588]Gauss Fibonacci的更多相关文章

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

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

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

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

  3. POJ3233 Matrix Power Series

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

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

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

  5. POJ3233 Matrix Power Series(矩阵快速幂+分治)

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

  6. POJ3233:Matrix Power Series(矩阵快速幂+递推式)

    传送门 题意 给出n,m,k,求 \[\sum_{i=1}^kA^i\] A是矩阵 分析 我们首先会想到等比公式,然后得到这样一个式子: \[\frac{A^{k+1}-E}{A-E}\] 发现要用矩 ...

  7. 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 ...

  8. POJ3233 Matrix Power Series(快速幂求等比矩阵和)

    题面 \(solution:\) 首先,如果题目只要我们求\(A^K\) 那这一题我们可以直接模版矩乘快速幂来做,但是它现在让我们求$\sum_{i=1}^{k}{(A^i)} $ 所以我们思考一下这 ...

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

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

随机推荐

  1. 用C#调用C++DLL提示找不到DLL解决方法【转】

    用C#调用自己写的C++ DLL(x64),总是提示找不到DLL,调试可以,发布release老是提示找不到DLL(dll文件确定存在) 原因:Visual C++的DLL分发方式没选:调试默认选择: ...

  2. L2 Regularization for Neural Nerworks

    L2 Regularization是解决Variance(Overfitting)问题的方案之一,在Neural Network领域里通常还有Drop Out, L1 Regularization等. ...

  3. github转gitee

    1.20190717,在SHH发现 下载github上的代码很慢(大概有422M),网上搜了 往文件“C:\Windows\System32\drivers\etc\hosts”中添加 ip& ...

  4. CPU高速缓存行与内存关系 及并发MESI 协议(转载)

    原文链接 http://www.cnblogs.com/jokerjason/p/9584402.html 先来一个整体图 一. 大致关系: CPU Cache --> 前端总线 FSB (下图 ...

  5. vc code 一个非常不错的插件

    https://marketplace.visualstudio.com/items?itemName=CoenraadS.bracket-pair-colorizer 这个是地址,前提下是安装了vc ...

  6. docker hub 本地镜像登录

    docker的登录信息存放在home目录下的.docker文件夹下,查看 cat ~/.docker/config.json { "auths": { "gcyimgs. ...

  7. Controller的返回值

    public String editItems(Model model) throws Exception { //itemsQueryVo参数如果没有的话 可以传一个null ItemsCustom ...

  8. idea2019.1 永久破解 亲测可用

    idea2019突然注册码突然失效了,搜了很多破解办法,这个还是有效的:https://www.jianshu.com/p/b6dd43618a66

  9. 进程池和multiprocess.Pool模块

    一.为什么要有进程池 首先,创建进程需要消耗时间,销毁进程也需要时间.其次,即使开启了成千上万的进程,操作系统也不能让它们同时执行,这样反而会影响程序的效率.因此我们不能无限制的根据任务开启或者结束进 ...

  10. C# 跨线程调用控件的4中方法

    原文:C# 跨线程调用控件 在C# 的应用程序开发中, 我们经常要把UI线程和工作线程分开,防止界面停止响应.  同时我们又需要在工作线程中更新UI界面上的控件, 下面介绍几种常用的方法 阅读目录 线 ...