【题解】佳佳的斐波那契数列(矩阵)

【题解】佳佳的斐波那契数列

题目描述

\(\Sigma i\times fib[i]\)的值

数据范围

\(n\le2^{31}-1\)

\(Solution\)

看数据范围就会做的题...

\[设 \\ f(n):=ib[n] \\ g(n)=nf(n) \\ s(n)=\Sigma^{i\le n}_{i=1}g(n) \]

然后

\[f(i)=f(i-1)+f(i-2) \\ s(i)=s(i-1)+g(i) \]

不好求\(g\),但是可以直接这样

\[g(i)=i\times f(i)\\ =i\times f(i-1)+i\times f(i-2) \\ =(i-1)f(i-1)+(i-2)f(i-2)+f(i-1)+2f(i-2) \\ =g(i-1)+g(i-2)+f(i-1)+2f(i-2) \]

于是我们构造一个行向量(矩阵)

\[k=\begin{pmatrix} \\ g(i)&g(i+1)&f(i)&f(i+1)&s(i)&s(i+1) \\ \\ \end{pmatrix} \]

然后想办法构造一个转移矩阵

\[k \times \begin{pmatrix}?\end{pmatrix}=\begin{pmatrix} \\ g(i+1)&g(i+2)&f(i+1)&f(i+2)&s(i+1)&s(i+2) \\ \\ \end{pmatrix} \]

就直接根据转移式构造一下

\[\begin{pmatrix}?\end{pmatrix}= \begin{pmatrix} 0&1&0&0&0&1 \\ 1&1&0&0&0&1 \\ 0&2&0&1&0&2 \\ 0&1&1&1&0&1 \\ 0&0&0&0&0&0 \\ 0&0&0&0&1&1 \end{pmatrix} \]

初始矩阵是

\[\begin{pmatrix} \\ 1&2&1&1&1&3 \\ \\ \end{pmatrix} \]

最后直接取出第五列就好了(\(s(i)\))

#include<bits/stdc++.h>

using namespace std;typedef long long ll;
template < class ccf >
inline ccf qr(ccf b){
    register char c=getchar();register int q=1;register ccf x=0;
    while(c<48||c>57)q=c==45?-1:q,c=getchar();
    while(c>=48&&c<=57)x=x*10+c-48,c=getchar();
    return q==-1?-x:x;}
inline int qr(){return qr(1);}
int mod,n;
const int maxn=7;
struct MTX{
    int data[maxn][maxn];
    MTX(){
	for(register int t=1;t<=6;++t)
	    for(register int i=1;i<=6;++i)
		data[t][i]=0;
    }
    inline int* operator [](register int x){return data[x];}
    inline void unis(){
	for(register int t=1;t<=6;++t)
	    for(register int i=1;i<=6;++i)
		data[t][i]=0;
	for(register int t=1;t<=6;++t)
	    data[t][t]=1;
    }
    
    inline void operator*=(MTX& f){
	MTX ret;
	for(register int k=1;k<=6;++k)
	    for(register int t=1;t<=6;++t)
		for(register int i=1;i<=6;++i)
		    ret[t][i]=(0ll+ret[t][i]+1ll*data[t][k]*f[k][i]%mod)%mod;
	*this=ret;
    }
    inline void operator ^=(const int&p){
	MTX base=*this,ret;ret.unis();
	for(register int t=p;t;base*=base,t>>=1)
	    if(t&1) ret*=base;
	*this=ret;
    }
}yyb;
ll vec[7]={0,1,2,1,1,1,3};

int main(){
    freopen("fib.in","r",stdin);
    freopen("fib.out","w",stdout);
    n=qr();mod=qr();
    if(n<=2){
	if(n< 1) printf("%d\n",0);
	if(n==1) printf("%d\n",1%mod);
	if(n==2) printf("%d\n",3%mod);
	return 0;
    }
    
    yyb[1][1]=0;yyb[1][2]=1;yyb[1][3]=0;yyb[1][4]=0;yyb[1][5]=0;yyb[1][6]=1;
    yyb[2][1]=1;yyb[2][2]=1;yyb[2][3]=0;yyb[2][4]=0;yyb[2][5]=0;yyb[2][6]=1;
    yyb[3][1]=0;yyb[3][2]=2;yyb[3][3]=0;yyb[3][4]=1;yyb[3][5]=0;yyb[3][6]=2;
    yyb[4][1]=0;yyb[4][2]=1;yyb[4][3]=1;yyb[4][4]=1;yyb[4][5]=0;yyb[4][6]=1;
    yyb[5][1]=0;yyb[5][2]=0;yyb[5][3]=0;yyb[5][4]=0;yyb[5][5]=0;yyb[5][6]=0;
    yyb[6][1]=0;yyb[6][2]=0;yyb[6][3]=0;yyb[6][4]=0;yyb[6][5]=1;yyb[6][6]=1;
    
    yyb^=n-1;
    
    ll ans=0;
    for(register int t=1;t<=6;++t)
	ans=(ans+(vec[t]*yyb[t][5])%mod)%mod;
    printf("%lld\n",ans);
    return 0;
}
posted @ 2019-05-03 14:04  谁是鸽王  阅读(324)  评论(1编辑  收藏  举报