LOJ #10222. 「一本通 6.5 例 4」佳佳的 Fibonacci 題解
如果之前推過斐波那契數列字首和就更好做(所以題目中給出了)。
先來推一下斐波那契數列字首和:
\[\sum\limits_{i=1}^nf(i) \]
其中 \(f(i)\) 表示Fibonacci數列第 \(i\) 項。
直接推式子:
記 \(s(x)=\sum\limits_{i=1}^xf(i)\)
將右邊一項項展開得出
\[f(1)=1 \]
\[f(2)=1 \]
\[f(3)=f(1)+f(2) \]
\[f(4)=f(2)+f(3) \]
\[... \]
\[f(n)=f(n-2)+f(n-1) \]
這些式子左右兩邊分別再加回去得出
\[s(n)=1+1+f(1)+f(n-1)+2*\sum_{i=2}^{n-2}f(i) \]
把其中一個 \(1\) 變成 \(f(1)\) 再和另一個 \(f(1)\) 加到 \(2*\sum\limits_{i=2}^{n-2}f(i)\) 裡面,得出
\[s(n)=1+f(n-1)+2*\sum_{i=1}^{n-2}f(i) \]
\[s(n)=1+f(n-1)+2*s(n-2) \]
\[s(n)-s(n-2)-s(n-2)=1+f(n-1) \]
\[f(n)+f(n-1)-s(n-2)=1+f(n-1) \]
\[f(n)-s(n-2)=1 \]
\[s(n-2)=f(n)-1 \]
令 \(n-2\) 變成 \(n\) 可得
\(s(n)=f(n+2)-1\)
注意到 \(f\) 是可以直接矩陣快速冪求的。這個時候就可以在 \(\mathcal{O}(\log n)\)
這個時候回來看本題:
對於 \(T(n)\) 來說,\(f(n)\) 被計算了 \(n\) 次,\(f(n-1)\) 被計算了 \((n-1)\) 次...
即
\[T(n)=\sum\limits_{i=1}^n{f(i)*i} \]
可以用字尾和的形式來表示這個式子,計 \(s2(i)=\sum\limits_{i=1}^n{f(i)}\)
所以上面的式子可以進一步轉化成這個字尾和的形式
\[T(n)=\sum\limits_{i=1}^n{s2(i)} \]
可是 \(n\) 又不確定,又不會推後綴和,應該怎麼求呢?
不會後綴和,但是我們會字首和啊!
用 \(s\) 表示上述式子即為
\[T(n)=\sum\limits_{i=1}^n{s(n)-s(i-1)} \]
把 \(s(n)\) 提出來:
\[T(n)=n*s(n)-\sum\limits_{i=1}^n{s(i-1)} \]
代入 \(s(i)=f(i+2)-1\)
\[T(n)=n*f(n+2)-n-\sum\limits_{i=1}^n{(f(i+1)-1)} \]
把 \(\sum\) 裡面的 \(-1\) 提出來
\[T(n)=n*f(n+2)-n-\sum\limits_{i=1}^n{f(i+1)}+n \]
之後就很簡單了。
\[T(n)=n*f(n+2)-n-\sum\limits_{i=2}^{n+1}{f(i)}+n \]
\[T(n)=n*f(n+2)-n-\sum\limits_{i=2}^{n+1}{f(i)}+f(1)-f(1)+n \]
\[T(n)=n*f(n+2)-n-\sum\limits_{i=1}^{n+1}{f(i)}-f(1)+n \]
化簡一下
\[T(n)=n*f(n+2)-s(n+1)-1 \]
\[T(n)=n*f(n+2)-(f(n+3)-1)-1 \]
\[T(n)=n*f(n+2)-f(n+3)+2 \]
矩陣快速冪求 \(f(n+2)\) 和 \(f(n+3)\) 就能 \(\mathcal{O}(\log n)\) 的時間複雜度求出 \(T(n)\) 了。
因為最後的式子裡面有個減法,可以提前在減法之前加上一個 \(m\) 來防止負數取模的情況發生。
參考 \(\mathcal{Code}\)
#include<iostream>
#include<cstdio>
#define ll long long
int n,m;
struct Matrix {
ll mat[3][3];
int n,m;
void memset() {
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
mat[i][j]=0;
}
};
Matrix mul(Matrix x,Matrix y)
{
Matrix z;
z.n=x.n;
z.m=y.m;
z.memset();
for(int i=1;i<=z.n;i++)
for(int j=1;j<=z.m;j++)
for(int k=1;k<=x.m;k++)
z.mat[i][j]=(z.mat[i][j]+x.mat[i][k]*y.mat[k][j])%m;
return z;
}
Matrix qpow(Matrix base,int y)
{
Matrix ans;
ans.n=ans.m=2;
ans.memset();
for(int i=1;i<=2;i++)
ans.mat[i][i]=1;
while(y)
{
if(y&1) ans=mul(ans,base);
base=mul(base,base);
y>>=1;
}
return ans;
}
ll f(int n)
{
Matrix ans,base;
ans.n=1;
ans.m=2;
base.n=base.m=2;
ans.memset();
base.memset();
ans.mat[1][1]=1;ans.mat[1][2]=1;
base.mat[1][1]=0;base.mat[1][2]=1;
base.mat[2][1]=1;base.mat[2][2]=1;
base=qpow(base,n-2);
ans=mul(ans,base);
return ans.mat[1][2];
}
int main()
{
scanf("%d%d",&n,&m);
printf("%lld",(n*f(n+2)%m-f(n+3)+m+2)%m);
return 0;
}