[洛谷P1939]【模板】矩阵加速(数列)

题目大意:给你一个数列a,规定$a[1]=a[2]=a[3]=1$,$a[i]=a[i-1]+a[i-3](i>3)$求$a[n] mod 10^9+7$的值。

解题思路:这题看似是很简单的递推,但是$nleq 2×10^9$,递推肯定是会超时的。故我们需要优化。

常见优化有矩阵加速,还有什么我并不知道了。

用矩阵可将此类题目时间复杂度从$O(n)$优化为$O(log_2 n)$。

具体对于此类形如$f(n)=f(n-1)*p(1)+f(n-2)*p(2)+...+f(n-k)*p(k)$的线性递推问题,有如下解法。

设$F[i]=egin{bmatrix} fn-k] \f[n-k+1]\f[n-k+2]\...\f[n-1]\f[n] end{bmatrix}quad$,

则$F[n]=egin{bmatrix} 0&1&0&0&...&0\0&0&1&0&...&0\0&0&0&1&...&0\...&...&...&...&...&...\0&0&0&0&...&1\p[k]&p[k-1]&p[k-2]&p[k-3]&...&p[1]end{bmatrix}quad ×F[n-1]$。

运用矩阵快速幂即可完成加速。

故此题解法如下。

$$egin{bmatrix}a[n-2]\a[n-1]\a[n]end{bmatrix}quad =egin{bmatrix}0&1&0\0&0&1\1&0&1end{bmatrix}^{n-3}quad×egin{bmatrix}a[1]\a[2]\a[3]end{bmatrix}quad$$

C++ Code:

#include<cstdio>
#include<cstring>
using namespace std;
struct mat{
    long long a[30][30];
    int r,c;
};
mat mul(mat x,mat y){
    mat ans;
    memset(&ans,0,sizeof ans);
    for(int i=0;i<x.r;++i)
    for(int j=0;j<y.c;++j)
    for(int k=0;k<x.c;++k)
    ans.a[i][j]=(ans.a[i][j]+x.a[i][k]*y.a[k][j])%1000000007;
    ans.r=x.r;
    ans.c=y.c;
    return ans;
}
void pow(int n){
    mat p;
    memset(&p,0,sizeof p);
    p.r=p.c=3;
    p.a[0][1]=p.a[1][2]=p.a[2][0]=p.a[2][2]=1;
    mat ans;
    memset(&ans,0,sizeof ans);
    ans.r=ans.c=3;
    ans.a[0][0]=ans.a[1][1]=ans.a[2][2]=1;
    while(n){
        if(n&1){
            ans=mul(p,ans);
        }
        p=mul(p,p);
        n>>=1;
    }
    p.a[0][0]=p.a[1][0]=p.a[2][0]=1;
    p.c=1;
    ans=mul(ans,p);
    printf("%d
",(int)ans.a[2][0]);
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        if(n<4)puts("1");else
        pow(n-3);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Mrsrz/p/7629374.html