斐波那契

转自:http://www.aichengxu.com/cyvyan/17027.htm

问题描述

斐波那契数列大家都非常熟悉。它的定义是:

f(x) = 1 .... (x=1,2)
f(x) = f(x-1) + f(x-2) .... (x>2)

对于给定的整数 n 和 m,我们希望求出:

f(1) + f(2) + ... + f(n) 的值。但这个值可能非常大,所以我们把它对 f(m) 取模。
公式如下

(Σ(1,n)f(i))%f(m)
但这个数字依然很大,所以需要再对 p 求模。

输入格式

输入为一行用空格分开的整数 n m p (0 < n, m, p < 10^18)

输出格式

输出为1个整数,表示答案

分析

这道题需要考虑斐波那契数列的多个性质。

性质1:Σ(1,n-2)f(i)=f(n)-1

证明:f(1)=f(3)-1,∴f(1)+f(2)=f(3)+f(2)-1=f(4)-1

以此类推,f(1)+f(2)+…+f(n-2)=f(n)-1

性质2:f(n+i)%f(n)=[f(i)*f(n-1)]%f(n) ,i>=1

证明:f(n+1)%f(n)=(f(n)+f(n-1))%f(n)=f(n-1)=f(1)*f(n-1)

f(n+2)%f(n)=(2f(n)+f(n-1))%f(n)=f(n-1)=f(2)*f(n-1)

……

f(n+i)%f(n)=(f(n+i-1)+f(n+i-2))%f(n)=[f(i)*f(n-1)]%f(n)

有了上述两个性质,题目就可以进行一些简化。

当n>=m时,原式=[f(m)-1 + f(m-1) + f(m) + f(m-1)*Σ(1,n-m)f(i)]%f(m)

=[f(m-1)*f(n-m+2)-1]%f(m)

当m=n+1时,原式=[f(m)-1 + f(m-1)]%f(m)=f(m-1)-1

当m>n+1时,原式=f(n+2)-1


问题描述
  斐波那契数列大家都非常熟悉。它的定义是:

  f(x) = 1 .... (x=1,2)
  f(x) = f(x-1) + f(x-2) .... (x>2)

  对于给定的整数 n 和 m,我们希望求出:
  f(1) + f(2) + ... + f(n) 的值。但这个值可能非常大,所以我们把它对 f(m) 取模。
  公式如下


  但这个数字依然很大,所以需要再对 p 求模。
输入格式
  输入为一行用空格分开的整数 n m p (0 < n, m, p < 10^18)
输出格式
  输出为1个整数,表示答案
样例输入
2 3 5
样例输出
0
样例输入
15 11 29
样例输出
25

#include <iostream>

#include <cstdio>
#include <cstring>
#include <cstdlib>
#define LENGTH 20000
using namespace std;

__int64 n,m,p;
int f[65][2][2][LENGTH];
bool check[65];
int answ[LENGTH];
int parray[LENGTH];

int getlen(int *array)
{
    int cnt=0;
    while(array[cnt]!=-1)
        cnt++;
    return cnt;
}

int *getmod(int* ,int*);

void print(int *array)
{
    int i;
    int para[LENGTH];
    memcpy(para,array,sizeof(para));
    int res[LENGTH];
    memcpy(res,getmod(para,parray),sizeof(res));
    int len = getlen(res);
    for(i=len-1;i>=0;i--)
        printf("%d",res[i]);
}

int compare(int *m1,int *m2)
{
    int l1=getlen(m1);
    int l2=getlen(m2);
    if(l1>l2)         return 1;
    else if(l1<l2)    return -1;
    else{
        for(int i=l1-1;i>=0;i--)
            if(m1[i]>m2[i])     return 1;
            else if(m1[i]<m2[i])       return -1;
        return 0;
    }
}

void l2str()
{
    int i=0;
    memset(parray,-1,sizeof(parray));
    while(p)
    {
        parray[i++] = p%10;
        p/=10;  
    }
}

void init()
{
    memset(f,-1,sizeof(f));
    memset(check,false,sizeof(check));
    f[0][0][0][0]=1;
    f[0][0][1][0]=0;
    f[0][1][0][0]=0;
    f[0][1][1][0]=1;
    f[1][0][0][0]=0;
    f[1][0][1][0]=1;
    f[1][1][0][0]=1;
    f[1][1][1][0]=1;
    check[0]=check[1]=true;
}

void add(int *m1,int *m2)
{
    int len1=getlen(m1);
    int len2=getlen(m2);
    int i;
    int c=0;
	for(i=len1;i<len2;i++)
		m1[i]=0;
	if(len1<len2)
		len1=len2;
    for(i=0;i<len2;i++)
    {
        m1[i] = m1[i]+m2[i]+c;
        if(m1[i]>=10)
        {
            m1[i]-=10;
            c=1;
        }
        else
            c=0;
    }
    for(;i<len1;i++)
    {
        if(c==0)    break;
        m1[i]++;
        if(m1[i]>=10) m1[i]-=10;
        else c=0;
    }
    if(i==len1 && c==1)
        m1[len1]=1;
}

void subtract(int *m1,int *m2)
{
    int len1=getlen(m1);
    int len2=getlen(m2);
    int i;
    int c=0;
    for(i=0;i<len2;i++)
    {
        m1[i] = m1[i]-m2[i]-c;
        if(m1[i]<0)
        {
            m1[i]+=10;
            c=1;
        }
        else
            c=0;
    }
    for(;i<len1;i++)
    {
        if(c==0)    break;
        m1[i] -= c;
        if(m1[i]<0) m1[i]+=10;
        else break;
    }
    i=len1-1;
    while(i>=0 && m1[i]==0)
    {
        m1[i]=-1;
        i--;
    }
    if(i==-1)
        m1[0]=0;
}

void multiply(int *m1,int *m2)
{
    int len1=getlen(m1);
    int len2=getlen(m2);
    int i,j,c;
    memset(answ,0,sizeof(answ));
    for(i=0;i<len2;i++)
    {
        c=0;
        for(j=0;j<len1;j++)
        {
            answ[i+j] += (m1[j]*m2[i]+c);
            c = answ[i+j]/10;
            answ[i+j]%=10;
        }
        while(c)
        {
            answ[i+j]=c%10;
            j++;
            c/=10;
        }
    }
    i=LENGTH-1;
    while(i>=0 && answ[i]==0)
    {
        answ[i]=-1;
        i--;
    }
	if(i==-1)
		answ[0]=0;
}

int *getmod(int *m1,int *m2)
{
    int i,j;
    int *remainder=(int *)malloc(LENGTH*sizeof(int));
    //memset(remainder,-1,sizeof(remainder));
    for(i=0;i<LENGTH;i++)
        remainder[i]=-1;
    int len=0,len1=getlen(m1),len2=getlen(m2);
    for(i=0;i<len1;i++)
    {
		for(j=len-1;j>=0;j--)
			remainder[j+1]=remainder[j];
        remainder[0]=m1[len1-i-1];
		len++;
        while((len>len2) || (len==len2 && compare(remainder,m2)>=0))
        {
            subtract(remainder,m2);
            len=getlen(remainder);
        }        
    }
    if(getlen(remainder)==0)
        remainder[0]=0;
    return remainder;
}

void mulMatrix(int m1[2][2][LENGTH],int m2[2][2][LENGTH])
{
    int t[2][2][LENGTH];
    memcpy(t,m1,sizeof(t));
    int array[LENGTH];

	multiply(t[0][0],m2[0][0]);
    memcpy(array,answ,sizeof(array));
	multiply(t[0][1],m2[1][0]);
    add(array,answ);
    memcpy(m1[0][0],array,sizeof(m1[0][0]));

	multiply(t[0][0],m2[0][1]);
	memcpy(array,answ,sizeof(array));
	multiply(t[0][1],m2[1][1]);
    add(array,answ);
    memcpy(m1[0][1],array,sizeof(m1[0][1]));

	multiply(t[1][0],m2[0][0]);
    memcpy(array,answ,sizeof(array));
	multiply(t[1][1],m2[1][0]);
    add(array,answ);
    memcpy(m1[1][0],array,sizeof(m1[1][0]));

    multiply(t[1][0],m2[0][1]);
	memcpy(array,answ,sizeof(array));
	multiply(t[1][1],m2[1][1]);
    add(array,answ);
    memcpy(m1[1][1],array,sizeof(m1[1][1]));
}

int *fabonacci(__int64 num)
{
    int matrix[2][2][LENGTH];
    memset(matrix,-1,sizeof(matrix));
    matrix[0][0][0]=1;
    matrix[0][1][0]=0;
    matrix[1][0][0]=0;
    matrix[1][1][0]=1;
    num--;
    int pos=1;
    while(num)
    {
        if(num%2)
        {
            mulMatrix(matrix,f[pos]);
        }
        num/=2;
        pos++;
        if(num)
        {
            if(!check[pos])
            {
                memcpy(f[pos],f[pos-1],sizeof(f[pos]));
                mulMatrix(f[pos],f[pos-1]);
                check[pos]=true;
            }    
        }
    }
    return matrix[1][1];
}

int main()
{
    freopen("data.txt","r",stdin);
    freopen("answer.txt","w",stdout);
    init();
    int temp[LENGTH];
    memset(temp,-1,sizeof(temp));
    temp[0]=1;
    scanf("%I64d%I64d%I64d",&n,&m,&p);
    l2str();
    int *pt;
	int a[LENGTH],b[LENGTH];
    if(n>=m)
    {
		
		memcpy(a,fabonacci(m-1),sizeof(a));
		memcpy(b,fabonacci(n-m+2),sizeof(b));
        multiply(a,b);
		memcpy(b,answ,sizeof(b));
        subtract(b,temp);
		memcpy(a,fabonacci(m),sizeof(a));
		pt=getmod(b,a);
    }
    else if(m==n+1)
    {
        memcpy(a,fabonacci(m-1),sizeof(a));
        pt = a;
        subtract(pt,temp);
    }
    else
    {
		memcpy(a,fabonacci(n+2),sizeof(a));
        pt = a;
        subtract(pt,temp);
    }
    print(pt);
	return 0;
}

Thinking:
设f(i)为斐波那契数列第i项,s(i)=f(1)+f(2)+...+f(i),
  i  1  2  3  4  5  6  7  8  9  10  11  12  13  14  15
f(i) 1  1  2  3  5  8 13 21 34  55  89  144 233 377 610
s(i) 1  2  4  7 12 20 33 54 88 143 232  376 609 ... ...
观察发现:
s(i)=f(i+2)-1 (i>0)
又:
s(i)%f(m)=(f(i+2)-1)%f(m)
 =f(i+2)%f(m)+f(m)-1
 =(f(i)+f(i+1))%f(m)+f(m)-1;
得到公式之后就好办多了,但是有一个问题,n,m,p的范围较大,必须用大整数+快速幂运算才能得满分

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值