矩阵快速幂

来源:互联网 发布:程序员可以兼职吗 编辑:程序博客网 时间:2024/06/15 11:45

写个矩阵快速幂的应用吧。
矩阵快速幂主要用来优化一些递推。先动手计算推出题目的递推公式或类似动归的状态转移方程,然后for一遍通常会超时,用矩阵快速幂来优化以做到log2 n的时间复杂度。
先学会矩阵快速幂:就是定义一下矩阵乘法,然后用快速幂即可,注意这里要将原来的1改为单位1(单位矩阵),就是左上到右下对角线是1,剩下是0的矩阵(自己推一下,这样才能保证它乘任何矩阵,原矩阵都不变)。
然后每道题有他的递推式,自己推出,然后构造矩阵。
例题
小澳的坐标系
( coordinate.cpp/c/pas)
【 题目描述】
小澳者表也,数学者景也,表动则景随矣。
小澳不喜欢数学,可数学却待小澳如初恋,小澳睡觉的时候也不放过。
小澳的梦境中出现了一个平面直角坐标系,自原点,向四方无限延伸。
小澳在坐标系的原点,他可以向上、向左或者向右走。他可以走 n 步, 但不
能经过相同的点。
小澳想知道他有多少种走法。
【 输入格式】
输入文件名为 coordinate.in。
输入文件仅第一行一个正整数 n,表示小澳可以走的步数。
【 输出格式】
输出文件名为 coordinate.out。
输出文件共一行,输出一个正整数, 表示答案(对 10^9+7 取模)。
【 输入输出样例 1】
coordinate.in coordinate.out
2 7
【输入输出样例 1 说明】
从(0,0)出发走 2 步,共 7 种走法:
(0,0)->(0,1)->(0,2)
(0,0)->(0,1)->(1,1)
(0,0)->(0,1)->(-1,1)
(0,0)->(1,0)->(2,0)
(0,0)->(1,0)->(1,1)
(0,0)->(-1,0)->(-2,0)
(0,0)->(-1,0)->(-1,1)
【 输入输出样例 2】
coordinate.in coordinate.out
3 17
【 数据规模与约定】
测试点编号 n
1~2 n<=10
3~4 n<=1005~6 n<=1000
7~8 n<=10^6
9~10 n<=10^9

我是推出了 f[i]=a[i]+2*b[i];a[i]=f[i-1];b[i]=a[i-1]+b[i-1];
但经一个哥们指点发现可以合为一个式子:f[i]=2*f[i-1]+f[i-2];实际结果一样,但更简练。于是就按这个写了。没想太清楚前两项咋弄,直接打表,第三项开始算。
构造 【0 1】
【1 2】 矩阵,用它乘【 3 7】,然后可以快速运算。

#include<iostream>#include<cstdio>#include<cstring>#define p 1000000007using namespace std;struct mat{    long long v[2][2];    mat(){memset(v,0,sizeof(v));}}ans,a;int n;mat c(mat a,mat b){    mat res;    for(int i=0;i<2;++i)     for(int j=0;j<2;++j)      for(int k=0;k<2;++k)        res.v[i][j]=(res.v[i][j]+(a.v[i][k]*b.v[k][j])%p)%p;    return res;}int main(){    freopen("coordinate.in","r",stdin);    freopen("coordinate.out","w",stdout);    scanf("%d",&n);    if(n==1){        printf("3");        return 0;    }    if(n==2){        printf("7");        return 0;    }    n-=2;    ans.v[0][0]=3;ans.v[0][1]=7;    a.v[0][0]=0;a.v[0][1]=1;    a.v[1][0]=1;a.v[1][1]=2;    mat aa;    aa.v[0][0]=aa.v[1][1]=1;    aa.v[0][1]=aa.v[1][0]=0;    while(n>0){        if(n&1)aa=c(aa,a);        a=c(a,a);        n>>=1;    }    ans=c(ans,aa);    printf("%I64d",ans.v[0][1]);    return 0;}
0 0
原创粉丝点击