各种斐波那契矩阵乘法快速幂

T1

f[1]=1; f[2]=1; f[n]=f[n-1]+f[n-2];
求f[n]

n<2^32

思路

暴力显然不行。
现在需要一种更强的方法:矩阵乘法。

考虑矩阵[f[n-1],f[n]]*A=[f[n],f[n-1]+f[n]]
推出矩阵A
[0,1]
[1,1]

因为矩阵乘法满足结合律
所以[f[1],f[2]]*A^n-1=[f[n-1],f[n]]

可用快速幂求出A^n-1

那么水就不贴代码了。

T2

f[1]=1; f[2]=1; f[n]=f[n-1]+f[n-2]+1;
求f[n]

思路

考虑矩阵[f[n-1],f[n],1]*A=[f[n],f[n-1]+f[n]+1,1]

得矩阵A
[0,1,0]
[1,1,0]
[0,1,1]

代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int x=3,mod=9973;
int a[x][x]={{0,1,0},{1,1,0},{0,1,1}},b[x]={1,1,1},c[x][x],n;
void power(int t)
{
    if(t==1) return;
    int d[x][x];
    memset(d,0,sizeof(d));
    for(int i=0; i<=x-1; i++) for(int j=0; j<=x-1; j++) d[i][j]=a[i][j];
    memset(c,0,sizeof(c));
    for(int i=0; i<=x-1; i++) for(int j=0; j<=x-1; j++)
    {
        for(int k=0; k<x; k++) c[i][j]=(c[i][j]+a[i][k]*a[k][j])%mod;
    }
    for(int i=0; i<=x-1; i++) for(int j=0; j<=x-1; j++) a[i][j]=c[i][j];
    memset(c,0,sizeof(c));
    power(t/2);
    memset(c,0,sizeof(c));
    if(t%2)
    {
        for(int i=0; i<=x-1; i++) for(int j=0; j<=x-1; j++)
        {
            for(int k=0; k<x; k++) 
                c[i][j]=(c[i][j]+a[i][k]*d[k][j])%mod;
        }
        for(int i=0; i<=x-1; i++) for(int j=0; j<=x-1; j++) a[i][j]=c[i][j];
    }
}
int main()
{
    scanf("%d",&n);
    n--;
    power(n);
    memset(c,0,sizeof(c));
    for(int j=0; j<=x-1; j++) for(int k=0; k<=x-1; k++)
    {
        c[0][j]=(c[0][j]+b[j]*a[k][j])%mod;
    }
    printf("%d",c[0][0]);
}

T3

求数列f[n]=f[n-2]+f[n-1]+n+1的第N项,其中f[1]=1,f[2]=1.

思路

其实也差不多

考虑矩阵[f[n-1],f[n],n+1,1]*A=[f[n],f[n-1]+f[n]+1+n,n+1,1]

得A

[0,1,0,0]
[1,1,0,0]
[0,1,1,0]
[0,1,1,1]

代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int x=4,mod=9973;
int a[x][x]={{0,1,0,0},{1,1,0,0},{0,1,1,0},{0,1,1,1}},b[x]={1,1,3,1},c[x][x],n;
void power(int t)
{
    if(t==1) return;
    int d[x][x];
    memset(d,0,sizeof(d));
    for(int i=0; i<=x-1; i++) for(int j=0; j<=x-1; j++) d[i][j]=a[i][j];
    memset(c,0,sizeof(c));
    for(int i=0; i<=x-1; i++) for(int j=0; j<=x-1; j++)
    {
        for(int k=0; k<x; k++) c[i][j]=(c[i][j]+a[i][k]*a[k][j])%mod;
    }
    for(int i=0; i<=x-1; i++) for(int j=0; j<=x-1; j++) a[i][j]=c[i][j];
    memset(c,0,sizeof(c));
    power(t/2);
    memset(c,0,sizeof(c));
    if(t%2)
    {
        for(int i=0; i<=x-1; i++) for(int j=0; j<=x-1; j++)
        {
            for(int k=0; k<x; k++) 
                c[i][j]=(c[i][j]+a[i][k]*d[k][j])%mod;
        }
        for(int i=0; i<=x-1; i++) for(int j=0; j<=x-1; j++) a[i][j]=c[i][j];
    }
}
int main()
{
    scanf("%d",&n);
    n--;
    power(n);
    memset(c,0,sizeof(c));
    for(int j=0; j<=x-1; j++) for(int k=0; k<=x-1; k++)
    {
        c[0][j]=(c[0][j]+b[k]*a[k][j])%mod;
    }
    printf("%d",c[0][0]);
}



T4

某天,幼儿园学生LZH周测数学时吓哭了,一道题都做不出来。这下可麻烦了他马上就会成为垫底的0分啊。他的期望也不高,做出最简单的第一题就够了
题目是这样的,定义F(n)=((根号5+1)/2)^(n-1) ,当然为了凸显题目的简单当然不能是小数分数或无理数,F(x)因此需要向上取整,当然求F(n)是非常难的!因此幼儿园园长头皮决定简单一点,求下F(x)的前n项和就行了。

题目大意

数列f[n]=f[n-1]+f[n-2],f[1]=f[2]=1的前n项和s[n]的快速求法

思路

设sigma(i=1,i<=n,f[i])为s[n]

考虑矩阵[f[n-1],f[n],s[n-1]]*A=[f[n],f[n-1]+f[n],s[n-1]+f[n]]

得A

[0,1,0]
[1,1,1]
[0,0,1]

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int x=3,mod=1000000007;
long long a[x][x]={{0,1,0},{1,1,1},{0,0,1}},b[x]={1,1,1},c[x][x],n;
void power(int t)
{
    if(t<=1) return;
    int d[x][x];
    memset(d,0,sizeof(d));
    for(int i=0; i<=x-1; i++) for(int j=0; j<=x-1; j++) d[i][j]=a[i][j];
    memset(c,0,sizeof(c));
    for(int i=0; i<=x-1; i++) for(int j=0; j<=x-1; j++)
    {
        for(int k=0; k<x; k++) c[i][j]=(c[i][j]+a[i][k]*a[k][j])%mod;
    }
    for(int i=0; i<=x-1; i++) for(int j=0; j<=x-1; j++) a[i][j]=c[i][j];
    memset(c,0,sizeof(c));
    power(t/2);
    memset(c,0,sizeof(c));
    if(t%2)
    {
        for(int i=0; i<=x-1; i++) for(int j=0; j<=x-1; j++)
        {
            for(int k=0; k<x; k++) 
                c[i][j]=(c[i][j]+a[i][k]*d[k][j])%mod;
        }
        for(int i=0; i<=x-1; i++) for(int j=0; j<=x-1; j++) a[i][j]=c[i][j];
    }
}
int main()
{
    scanf("%d",&n);
    n--;
    if(!n)
    {
        printf("1");return 0;
    }
    power(n);
    memset(c,0,sizeof(c));
    for(int j=0; j<=x-1; j++) for(int k=0; k<=x-1; k++)
    {
        c[0][j]=(c[0][j]+b[k]*a[k][j])%mod;
    }
    printf("%d",c[0][2]);
}


T5

这天,当一头雾水的LZH同学在考场上痛哭的时候,一旁的YMW早就如切菜一样cut掉了简单至极的第一题,风轻云淡的冲击着满分,然而最后一道题着实难道了他,毕竟是幼儿园副园长树皮和著名毒瘤秋彪为了防止人AK而出的,可是YMW作为ACrush的著名粉丝,向来以AK为目标,永不言败,而他能不能AK就看你了
题目是酱紫的,f(n)-f(3)-f(4)-f(5)-…-f(n-3)-f(n-2)=(n+4)(n-1)/2,f(1)=1,f(2)=1
求f(n)的前n项和

题目大意

数列f[n]=f[n-1]+f[n-2]+n+1,f[1]=f[2]=1的前n项和s[n]的快速求法

思路

[f[n-1],f[n],s[n-1],n+1,1]*A=[f[n],f[n-1]+f[n]+n+1,s[n-1]+f[n],n+1,1]

A=
[0,1,0,0,0]
[1,1,1,0,0]
[0,0,1,0,0]
[0,1,0,1,0]
[0,1,0,1,1]

代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int x=5,mod=1000000007;
long long a[x][x]={{0,1,0,0,0},
                   {1,1,1,0,0},
                   {0,0,1,0,0},
                   {0,1,0,1,0},
                   {0,1,0,1,1}},b[x]={1,1,1,3,1},c[x][x],n;
void power(int t)
{
    if(t<=1) return;
    int d[x][x];
    memset(d,0,sizeof(d));
    for(int i=0; i<=x-1; i++) for(int j=0; j<=x-1; j++) d[i][j]=a[i][j];
    memset(c,0,sizeof(c));
    for(int i=0; i<=x-1; i++) for(int j=0; j<=x-1; j++)
    {
        for(int k=0; k<x; k++) c[i][j]=(c[i][j]+a[i][k]*a[k][j])%mod;
    }
    for(int i=0; i<=x-1; i++) for(int j=0; j<=x-1; j++) a[i][j]=c[i][j];
    memset(c,0,sizeof(c));
    power(t/2);
    memset(c,0,sizeof(c));
    if(t%2)
    {
        for(int i=0; i<=x-1; i++) for(int j=0; j<=x-1; j++)
        {
            for(int k=0; k<x; k++) 
                c[i][j]=(c[i][j]+a[i][k]*d[k][j])%mod;
        }
        for(int i=0; i<=x-1; i++) for(int j=0; j<=x-1; j++) a[i][j]=c[i][j];
    }
}
int main()
{
    scanf("%d",&n);
    n--;
    if(!n)
    {
        printf("1");return 0;
    }
    power(n);
    memset(c,0,sizeof(c));
    for(int j=0; j<=x-1; j++) for(int k=0; k<=x-1; k++)
    {
        c[0][j]=(c[0][j]+b[k]*a[k][j])%mod;
    }
    printf("%d",c[0][2]);
}








猜你喜欢

转载自blog.csdn.net/eric1561759334/article/details/80286508
今日推荐