UVA11149 Power of Matrix(快速幂求等比矩阵和)

题面



\(solution:\)

首先这一题是\(UVA11149\)的题目,建议到\(vjudge\)上去测,没办法\(UVA\)太难注册了。然后其原题与本题不是完全一样的,毒瘤卡输出!但思想一模一样!

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

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

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

我们设\(B^x=A^1+A^2+.....+A^x\) 根据上面第四个的原理我们可以得到:

  1. \(B^1=A^1\)
  2. \(B^2=A^1+A^1*A^1=B^1+B^1*A^1\)
  3. \(B^4=(A^1+A^2)+A^2*(A^1+A^2)=B^2+A^2*B^2\)
  4. \(B^8=(A^1+A^2+A^3+A^4)+A^4*(A^1+A^2+A^3+A^4)=B^4+A^4*B^4\)
  5. \(B^{16}==B^8+A^8*B^8\)

而我们要得到的最终结果就是\(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*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;
}

原文地址:https://www.cnblogs.com/812-xiao-wen/p/10385473.html

时间: 2024-08-29 07:04:59

UVA11149 Power of Matrix(快速幂求等比矩阵和)的相关文章

POJ 3070-Fibonacci(矩阵快速幂求斐波那契数列)

Fibonacci Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 3070 Appoint description:  System Crawler  (2015-02-28) Description In the Fibonacci integer sequence, F0 = 0, F1 = 1, and Fn = Fn ? 1 +

hdu 3221 Brute-force Algorithm(快速幂取模,矩阵快速幂求fib)

http://acm.hdu.edu.cn/showproblem.php?pid=3221 一晚上搞出来这么一道题..Mark. 给出这么一个程序,问funny函数调用了多少次. 我们定义数组为所求:f[1] = a,f[2] = b, f[3] = f[2]*f[3]......f[n] = f[n-1]*f[n-2].对应的值表示也可为a^1*b^0%p,a^0*b^1%p,a^1*b^1%p,.....a^fib[n-3]*b^fib[n-2]%p.即a,b的指数从n=3以后与fib数列

poj 3070 Fibonacci (矩阵快速幂求斐波那契数列的第n项)

题意就是用矩阵乘法来求斐波那契数列的第n项的后四位数.如果后四位全为0,则输出0,否则 输出后四位去掉前导0,也...就...是...说...输出Fn%10000. 题目说的如此清楚..我居然还在%和/来找后四位还判断是不是全为0还输出时判断是否为0然后 去掉前导0.o(╯□╰)o 还有矩阵快速幂的幂是0时要特判. P.S:今天下午就想好今天学一下矩阵乘法方面的知识,这题是我的第一道正式接触矩阵乘法的题,欧耶! #include<cstdio> #include<iostream>

数论——快速幂,模运算及快速幂求逆元

一.快速幂 原理: 快速幂的原理十分简单. ak=a2^0*a2^1*a2^2*…a2^x,其中k=20+21+22+…+2x. 这显然是正确的.因为任何一个数都可以表示成二进制. 接下去利用位运算实现即可. 代码实现 模板题链接:快速幂 代码模板如下:时间复杂度O(logk) int qmi(int a,int k,int p) { int res=1%p; while(k) { if(k&1)res=(long long)res*a%p; a=(long long)a*a%p; k>&g

2017省夏令营Day7 【快速幂,筛法,矩阵快速幂,线段树】

题解:首先,我们可以得到一个规律:经过2次变换后,a和b的值都分别乘2了,所以只要用快速幂就能过啦,但是,要特判n为0的情况. 代码如下: 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #define Mod 1000000007 5 using namespace std; 6 long long a,b,n,ans1,ans2; 7 long long power(long long x)

矩阵乘法&amp;&amp;矩阵快速幂&amp;&amp;最基本的矩阵模型——斐波那契数列

矩阵,一个神奇又令人崩溃的东西,常常用来优化序列递推 在百度百科中,矩阵的定义: 在数学中,矩阵(Matrix)是一个按照长方阵列排列的复数或实数集合 ,最早来自于方程组的系数及常数所构成的方阵.这一概念由19世纪英国数学家凯利首先提出. 好,很高深对吧.那我们就更加直接地理解一下矩阵的实质:二维数组 好了这个SB都会,就不解释了 同二维数组一样,矩阵是一个'纵横排列的二维数据表格',它一般是一个n*m的二维数组,其中n*m表示它有n行m列 每一位上的数可以用下标i,j来表示,形如这样一个矩阵:

poj 3070 Fibonacci 【矩阵快速幂 求第N个斐波那契数%1000】

Fibonacci Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11123   Accepted: 7913 Description In the Fibonacci integer sequence, F0 = 0, F1 = 1, and Fn = Fn ? 1 + Fn ? 2 for n ≥ 2. For example, the first ten terms of the Fibonacci sequenc

hdu4686 简单的矩阵快速幂求前n项和

HDU4686 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4686 题意:题目说的很清楚了,英语不好的猜也该猜懂了,就是求一个表达式的前n项和,矩阵快速幂一般多加一行一列来完成这个加的操作.具体看代码吧.比较简单,唯一有一点坑的地方,就是ax和bx可能比较大,在求ax*bx的时候,要考虑溢出的问题,需要先mod.其他没有了,直接看代码吧! //Author: xiaowuga #include <bits/stdc++.h> #define

hdu 2837 Calculation【欧拉函数,快速幂求指数循环节】

欢迎关注__Xiong的博客: http://blog.csdn.net/acmore_xiong?viewmode=list Calculation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1912    Accepted Submission(s): 413 链接:click me Problem Description A