矩阵快速幂+递推

矩阵快速幂+递推_第1张图片
由题意易得递推式:
f[i]=f[i-1]+f[i-2]*4+f[i-3]*2
其中长度为1的消除方法只有一种,长度为2的消除方法是4种(不包括与长度为1重复的一种),长度为三的消除方法一共有2种。
注意,f[0]=1。
但由于数据量巨大!!!(giant)我们想到了矩阵快速幂的优化。
下面一起来推一推:
用类似fibonacci矩阵乘法的方法,这里用到了一个3*3的矩阵。
首先答案矩阵是:
{f[i]
f[i+1]
f[i+2]}
要将它变成矩阵:
{f[i+1]
f[i+2]
f[i+3]}
只需用计算矩阵:
{0 1 0
0 0 1
2 4 1} 乘上 答案矩阵 即可。
所以只需要将计算矩阵自乘n-3次,再将得到的矩阵第三行相加即使答案。代码:

#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int mod=1000000007;
LL n;
struct node{
    LL g[4][4];
    void init(){
        g[1][1]=g[1][3]=g[2][1]=g[2][2]=0;
        g[1][2]=g[2][3]=1;g[3][1]=2;
        g[3][2]=4;g[3][3]=1;
    }
};
node operator *(node A,node B){
    node ret;
    memset(ret.g,0,sizeof(ret.g));
    for(int i=1;i<=3;i++)
        for(int j=1;j<=3;j++)
            for(int k=1;k<=3;k++)
                ret.g[i][j]=(ret.g[i][j]+(A.g[i][k]*B.g[k][j])%mod)%mod;
    return ret;
}
node pow(node a,LL b){
    bool flag=false;
    node ans;
    while(b){
        if(b&1LL){
            if(!flag) ans=a;
            else ans=ans*a;
            flag=true;
        }
        a=a*a;
        b>>=1;
    }
    return ans;
}
int main(){
    scanf("%lld",&n);
    if(n==0) printf("1");
    else if(n==1) printf("1");
    else if(n==2) printf("5");
    else if(n==3) printf("11");
    else{
        node a;
        a.init();
        a=pow(a,n-3);
        printf("%lld",(a.g[3][1]*1+a.g[3][2]*5+a.g[3][3]*11)%mod);
    }
    return 0;
}

^_^

你可能感兴趣的:(递推,矩阵快速幂)