本题的找规律题解到此为止。
为防止新人受到误导,不再接受新的此类题解。
以前的保留不会删除,但请不要再提交。
题目传送门。
矩阵加速模板题吧。给一个正经的不用找规律的做法。
考虑设 \(F_n\) 表示前 \(n\) 个格子的答案,\(f_n\) 表示最后降落在 \(n\) 的方案数,显然有 \(F_n=F_{n-1}+f_n\),由于 \(f_n\) 也是由一个 \(f\) 的前缀和得来,所以得到 \(F_{n}=F_{n-1}+F_{n-m-1}\)。
这个长得就很矩阵加速了。观察数据范围发现 \(m\) 很小,而这又是一个前缀和的形式,启示我们把 \(\{F_n,F_{n-1},\cdots,F_{n-m}\}\) 都放入一个矩阵里进行转移。
考虑用原矩阵 \(\begin{bmatrix} F_{n-1}\\ F_{n-2}\\ \cdots\\ F_{n-m-1} \end{bmatrix}\) 推出目标矩阵 \(\begin{bmatrix} F_{n}\\ F_{n-1}\\ \cdots\\ F_{n-m} \end{bmatrix}\)
对于 \(i\) 满足 \(n-m\le i\le n-1\),\(F_i\) 都是原矩阵已知的元素,不用管它。
对于 \(F_n\),把它直接替换成 \(F_{n-1}+F_{n-m-1}\),这两项恰好也是我们原矩阵已知的元素。
下面构造转移矩阵。
第一行是特殊的,因为它的转移是对于 \(F_n\) 的。我们将第一个设成 \(1\),最后一个设成 \(1\),其余设成 \(0\),表示对应 \(F_{n-1}\) 和 \(F_{n-m-1}\)。
然后剩下的那些行,只需要将 \(F_i\) 对应的位置设成 \(1\) 就可以,直接继承过来。
这样就得到了这样一个矩阵(这是当 \(m=5\) 时矩阵的样子,来类比一下,应该很容易能看出来):
\[\begin{bmatrix} 1 & 0 & 0 & 0 & 0 & 1\\ 1 & 0 & 0 & 0 & 0 & 0\\ 0 & 1 & 0 & 0 & 0 & 0\\ 0 & 0 & 1 & 0 & 0 & 0\\ 0 & 0 & 0 & 1 & 0 & 0\\ 0 & 0 & 0 & 0 & 1 & 0 \end{bmatrix}\]这样的话,可以构造一个 \(\left(m+1\right)\times \left(m+1\right)\) 的转移矩阵然后快速幂即可。
矩阵乘法 \(\Theta(m^3)\),快速幂 \(\Theta(\log n)\),最终复杂度 \(\Theta(m^3\log n)\)。
代码:
const int MOD(1e9+7); inline int add(int x,int y){return x+y>=MOD?x+y-MOD:x+y;} inline int mul(int x,int y){return 1ll*x*y%MOD;} ll n; int m; struct Matrix { int G[30][30]; Matrix(){rep(i,1,m) rep(j,1,m) G[i][j]=0;return;} Matrix operator*(const Matrix&x) { Matrix res; rep(i,1,m) rep(j,1,m) rep(k,1,m) res.G[i][j]=add(res.G[i][j],mul(G[i][k],x.G[k][j])); return res; } }; inline Matrix ksm(ll y) { Matrix ans,x; rep(i,1,m) ans.G[i][i]=1; rep(i,2,m) x.G[i][i-1]=1; x.G[1][1]=1,x.G[1][m]=1; while(y) { if(y&1) ans=ans*x; x=x*x; y>>=1; } return ans; } int main() { scanf("%lld%d",&n,&m); ++m; Matrix now=ksm(n+m-1); printf("%d\n",now.G[1][1]); return 0; }