斐波那契
来源:互联网 发布:淘宝苹果组装机 编辑:程序博客网 时间:2024/04/30 12:50
转自: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 求模。
#include <iostream>
#include <cstdio>#include <cstring>#include <cstdlib>#define LENGTH 20000using 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;}
- 斐波那契
- 斐波那契
- 斐波那契
- 斐波那契
- 斐波那契
- 斐波那契
- 斐波那契
- 斐波那契
- 【斐波那契】
- 斐波那契
- 斐波那契
- 斐波那契
- 斐波那契
- 斐波那契
- 斐波那契
- 斐波那契
- 斐波那契
- 斐波那契
- 给一个不多于5位的正整数,要求:一、求它是几位数,二、逆序打印出各位数字。
- 公钥密码之RSA密码算法扩展欧几里德求逆元!!
- android 获取本地视频文件以及缩略图
- c++的继承与虚继承
- 洛谷P1218 特殊的质数肋骨
- 斐波那契
- UICollectionView
- 字符串全排列算法学习总结
- 图片处理.md
- Android 大批量图片显示时候如何避免OOM
- Java JDBC基础
- flexigrid使用心得
- BZOJ 1008 [HNOI2008] 越狱
- Add Digits