JZOJ 1240. Fibonacci sequence

来源:互联网 发布:防止sql注入的函数 编辑:程序博客网 时间:2024/05/21 07:10

原题

截图

题解

  • 对于80%的数据,根据递推式用O(n)的方法就可以了。

  • 对于100%的数据,显然要用到矩阵方法,这里介绍两种思路。

  • F(n)S(n) 分别为 Fibonaccisequence 的第n项和前n项和。

  • 求第x~y项的和相当于求 S(y)S(x1)

  • 于是问题变成了怎么求 S(y)S(x1)

      • S(n) 的通项,和 F(n) 的通项比较。

      • 可以发现 S(n)=F(n+2)1,于是就用矩阵乘法求出数列的第 N+2 项。

      • 但这样的方法在比赛中不可取,因为,

      • f(n)=55[(1+52)n(152)n]

      • S(n)=55[(1+52)n+2(152)n+2]1

      • 显然除非你的手算能力足够强,否则这需要浪费大量时间才能推倒出来。

      • 当然,由于 S(n)=F(n+2)1 规律还是优美的。

      • 善于观察的同写几项出来就可以发现规律.

      • 根据 f(n)=f(n1)+f(n2)S(n)=S(n1)+f(n)

      • 我们可以按如下方法构造一个矩阵。

      • [f(n)f(n1)S(n)]=[f(n1)f(n2)S(n1)]110100111

      • 这种方法比较直观,对矩阵乘法比较熟悉的同学应该很容易想到.

Code

#include<cstdio>#include<cstring>using namespace std;int mid[2][2],s[2][2],c[2];int mid1[2][2],mid2[2][2];int ans1[2],ans2[2];const int mo=10000;inline int read(){    int data=0; char ch=0;    while(ch<'0' || ch>'9') ch=getchar();    while(ch>='0' && ch<='9') data=data*10+ch-'0',ch=getchar();    return data;}//读入优化inline void ksm1(int v){    int ans[2][2];    ans[0][0]=ans[1][1]=1;    ans[1][0]=ans[0][1]=0;    while(v)    {        if(v%2)        {            memset(s,0,sizeof(s));            for(int i=0;i<2;i++)                for(int j=0;j<2;j++)                    for(int k=0;k<2;k++)                        s[i][j]=(s[i][j]+ans[i][k]*mid1[k][j])%mo;            memcpy(ans,s,sizeof(ans));        }        memset(s,0,sizeof(s));        for(int i=0;i<2;i++)            for(int j=0;j<2;j++)                for(int k=0;k<2;k++)                    s[i][j]=(s[i][j]+mid1[i][k]*mid1[k][j])%mo;        memcpy(mid1,s,sizeof(mid1));        v/=2;    }    memcpy(mid1,ans,sizeof(mid1));}//快速幂前x-1项inline void ksm2(int v){    int ans[2][2];    ans[0][0]=ans[1][1]=1;    ans[1][0]=ans[0][1]=0;    while(v)    {        int s[2][2];        if(v%2)        {            memset(s,0,sizeof(s));            for(int i=0;i<2;i++)                for(int j=0;j<2;j++)                    for(int k=0;k<2;k++)                        s[i][j]=(s[i][j]+ans[i][k]*mid2[k][j])%mo;            memcpy(ans,s,sizeof(ans));        }        memset(s,0,sizeof(s));        for(int i=0;i<2;i++)            for(int j=0;j<2;j++)                for(int k=0;k<2;k++)                    s[i][j]=(s[i][j]+mid2[i][k]*mid2[k][j])%mo;        memcpy(mid2,s,sizeof(mid2));        v/=2;    }    memcpy(mid2,ans,sizeof(mid2));}//快速幂前y项int main(){    mid[0][1]=mid[1][1]=mid[1][0]=1;    int T=read();    while(T--)    {        int x=read(),y=read();        ans1[0]=ans1[1]=ans2[0]=ans2[1]=1;        memcpy(mid1,mid,sizeof(mid1));        memcpy(mid2,mid,sizeof(mid2));        ksm1(x-1);        ksm2(y);        memset(c,0,sizeof(c));        for(int i=0;i<2;i++)            for(int j=0;j<2;j++)                c[i]=(c[i]+ans1[j]*mid1[i][j])%mo;        memcpy(ans1,c,sizeof(ans1));        memset(c,0,sizeof(c));        for(int i=0;i<2;i++)            for(int j=0;j<2;j++)                c[i]=(c[i]+ans2[j]*mid2[i][j])%mo;//矩阵乘法        memcpy(ans2,c,sizeof(ans2));        printf("%d\n",(ans2[1]+mo-ans1[1])%mo);//相减得区间和    }    return 0;}
1 1
原创粉丝点击