[洛谷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$的值。

解题思路:这题看似是很简单的递推,但是$n\leq 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]=\begin{bmatrix} fn-k] \\f[n-k+1]\\f[n-k+2]\\...\\f[n-1]\\f[n] \end{bmatrix}\quad$,

则$F[n]=\begin{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]$。

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

故此题解法如下。

$$\begin{bmatrix}a[n-2]\\a[n-1]\\a[n]\end{bmatrix}\quad =\begin{bmatrix}0&1&0\\0&0&1\\1&0&1\end{bmatrix}^{n-3}\quad×\begin{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\n",(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;
}

 

posted @ 2017-10-05 16:34  Mrsrz  阅读(1286)  评论(0编辑  收藏  举报