矩阵——P1962 斐波那契数列

https://www.luogu.org/problem/show?pid=1962
嗯……………………
代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#define Ll long long
using namespace std;
struct jv{
    int n,m;
    Ll a[3][3];
    jv(){n=m=0;memset(a,0,sizeof a);}
}a,ans,c;
Ll n,mo=1000000007;
jv cheng(jv a,jv b){
    jv ans; ans.n=a.n; ans.m=b.m;
    for(int i=1;i<=a.n;i++)
        for(int k=1;k<=a.m;k++)if(a.a[i][k])
            for(int j=1;j<=b.m;j++)
                ans.a[i][j]=(ans.a[i][j]+a.a[i][k]*b.a[k][j])%mo;
    return ans; 
}
int main()
{
    scanf("%lld",&n);
    if(n<3){printf("1");return 0;}
    n-=3;
    a.n=a.m=2;
    a.a[1][1]=a.a[1][2]=a.a[2][1]=1;
    ans=a;
    while(n){
        if(n&1)ans=cheng(ans,a);
        n>>=1;
        a=cheng(a,a);
    }
    c.n=2; c.m=1;
    c.a[1][1]=c.a[2][1]=1;
    ans=cheng(ans,c);
    printf("%lld",ans.a[1][1]);
}

首先我们定义一个struct

struct jv{
    int n,m;
    Ll a[3][3];
    jv(){n=m=0;memset(a,0,sizeof a);}
};

更新矩阵的时候千万不要把n,m漏掉;
那么我们咋么矩乘呢;
两个矩阵
第一个矩阵的列和第二个矩阵的行一定要相同;
所以我们可以把一个矩阵的列与第二个矩阵的行相乘合并,组成一个新的矩阵,新矩阵的行是第一个矩阵的行,列是第二个矩阵的列;
这里写图片描述

新矩阵的[1,1]是第一个矩阵的Σ[1,k]*[k,1] (k=1->n)
新矩阵的[1,2]是第一个矩阵的Σ[1,k]*[k,2] (k=1->n)
…..
新矩阵的[i,j]是第一个矩阵的Σ[i,k]*[k,j] (k=1->n)

这里写图片描述
所以说相乘代码

jv cheng(jv a,jv b){
    jv ans;    ans.n=a.n; ans.m=b.m;
    for(int i=1;i<=a.n;i++)
        for(int j=1;j<=b.m;j++)
            for(int k=1;k<=a.m;k++)
                ans.a[i][j]=(ans.a[i][j]+a.a[i][k]*b.a[k][j])%mo;
    return ans;    
}

这个就是模拟;
当然还是有优化的;

jv cheng(jv a,jv b){
    jv ans; ans.n=a.n; ans.m=b.m;
    for(int i=1;i<=a.n;i++)
        for(int k=1;k<=a.m;k++)if(a.a[i][k])
            for(int j=1;j<=b.m;j++)
                ans.a[i][j]=(ans.a[i][j]+a.a[i][k]*b.a[k][j])%mo;
    return ans; 
}

这样更快,快到飞起;



关于斐波那契;
我们先搞一刁矩阵;
这里写图片描述
我们先考虑怎么跟新f[n-1],f[n-2]…
显然只要把f[n]给f[n-1],f[n-1]给f[n-2]就好了;
所以斐波那契的矩阵
这里写图片描述
自己模拟模拟把

那么对于f[n]
如果f[n]=f[n-1]-2*f[n-2]+6*f[n-3]
那么
这里写图片描述
想通的话显然得不行

posted @ 2017-05-02 14:11  largecube233  阅读(157)  评论(0编辑  收藏  举报