标签:turn clu c++ begin 矩阵加速 void while div cstring
题目大意:给你一个数列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} F[n-k] \\F[n-k+1]\\F[n-k+2]\\...\\F[2]\\F[1] \end{bmatrix}\quad$,
则$F[n]=F[n-1]*\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$。
运用矩阵快速幂即可完成加速。
故此题解法如下。
$$\begin{bmatrix}F[n-2]\\F[n-1]\\F[n]\end{bmatrix}\quad =\begin{bmatrix}0&1&0\\0&0&1\\1&0&1\end{bmatrix}^{n-1}\quad×\begin{bmatrix}F[1]\\F[2]\\F[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(ans,p); } p=mul(p,p); n>>=1; } p.a[0][0]=p.a[0][1]=p.a[0][2]=1; p.c=1; mul(ans,p); printf("%d\n",(int)ans.a[2][2]); } int main(){ int t; scanf("%d",&t); while(t--){ int n; scanf("%d",&n); if(n<4)puts("1");else pow(n-1); } return 0; }
标签:turn clu c++ begin 矩阵加速 void while div cstring
原文地址:http://www.cnblogs.com/Mrsrz/p/7629374.html