HDU 3117 由n^k的前4位,推出(斐波那契)矩阵^k的前四位
来源:互联网 发布:淘宝一个差评多少钱 编辑:程序博客网 时间:2024/05/29 08:22
http://acm.hdu.edu.cn/showproblem.php?pid=3117
Fibonacci Numbers
What is the numerical value of the nth Fibonacci number?
There is no special way to denote the end of the of the input, simply stop when the standard input terminates (after the EOF).
0123453536373839406465
0112359227465149303522415781739088169632459861023...41551061...77231716...7565
思路:后4位,很好做,矩阵快速幂就可以了,(至于矩阵快速幂的原理就不介绍了)
F2=2 , F1=1 , F0=1 , F(-1)=0 , F(-2)=1;按照斐波那契规律再往前推两项 (这样就避免了特判,或者是避免了n--了)
初始矩阵 系数矩阵 第n个矩阵的左上角的数字代表第n项斐波那契数,第n个矩阵=初始矩阵*系数矩阵的^n;(都%10000)
F(-1)0 F(-2)=1 1 1
0 0 1 0
前4位的方法,跟网上其他代码不一样,我按照自己的思路打的代码。
首先介绍一下,求n^k的前4位怎么求,n是数字,k是次方。首先我令10^p=n^k;则有p=logn^k=k*logn;(log都是以10为底的)
p求着很简单,有了这个p我就能算出n^k,现在double x=(int)p; y=p-x; y是p的小数部分,x是p的整数部分。
p=x+y, so: 10^x * 10^y =10^p =n^k;(这个式子没毛病吧) 那么10^x代表的是什么,也就是1后面x个0而已。
现在我只需要知道n^k的前4位数字,因为10^y= (n^k) / (10^x); 因为10^x是10的整数倍,(n^k) / (10^x)就只是n^k把小数点往左移x位,数字是不变的,所以只需要知道y即可知道n^k的前几位数字。
(int)(10^y *1000) 就表示n^k的前4位数字。
计算方法:
double p=k*log(n);
p=p-(int)p;
int ans=(int)(pow(10,p)*1000);
懂了求n^k的前4位,再说这道题。这道题的n不是数字了,n表示一个矩阵。
只要求出p即可;n现在是矩阵了,如果我令10^p=n,然后再快速幂也可以(可是这个式子明显是不对的,n是矩阵,p还是没法求),由这个式子再思考一下,我们能不能反过来,让n=10^p;(这个式子就有可能对了),n表示一个矩阵,矩阵里面有数字,我都表示成10的p次方不就行了(矩阵里面的数字都是次方数p),这时候用快速幂求出n^k,不就知道了p。
所以现在构造的矩阵n里的数字已经不能是表示数字的了,应该是该数字转换成10^p的(double)p了,所以矩阵对应的数字改一下即可。
原来的 初始矩阵 系数矩阵
0 1 1 1
0 0 1 0
(因为10的任何次方也不可能为0,又因为斐波那契额数不会小于1大于0的,所以把原来的0统统写成负数) (是负数则特判就行了)
变过来就成了
初始矩阵(double) 系数矩阵(double)
-1 0 0 0 (0表示1及10^0) (若是2的话就表示100及10^2)
-1 -1 0 -1 (-1表示原来的数字是0,遇到-1则特判即可)
原来的矩阵乘法也会改变,数字乘法 会变成 次方的乘法。数字加法 会变成 次方的加法
100*100=10000,及2+2=4;(乘法)
100+100=200,及2+log(pow(10,2-2)+1)=(double)log2+2;(加法)
再举个加法例子
数字加法 10^5.5+10^3.6=10^3.6 * (10^1.9+1)
次方加法 5.5+3.6=3.6+log ( pow( 10 , 1.9 ) + 1 );跟上面的一一对应。
奉上我的AC代码:
#include <iostream>#include <queue>#include<cstring>#include<cstdio>#include <cmath>#include<algorithm>#define LL long long#define mod 2008using namespace std;int f[100];struct node2//计算前4位的矩阵{ double b[5][5];};node2 operator *(node2 a,node2 b)//跟矩阵乘法类似{ node2 c; for(int i=0; i<2; i++) for(int j=0; j<2; j++) { double ma,mb; int flag1=0,flag2=0;//标记,记录是否有-1出现。 if(a.b[i][0]<0||b.b[0][j]<0) flag1=1; else ma=a.b[i][0]+b.b[0][j]; if(a.b[i][1]<0||b.b[1][j]<0) flag2=1; else mb=a.b[i][1]+b.b[1][j]; if(flag1&&flag2) c.b[i][j]=-1.0; else if(flag1&&!flag2) c.b[i][j]=mb; else if(!flag1&&flag2) c.b[i][j]=ma; else { double mc; if(mb>=ma) swap(mb,ma); mc=mb; ma-=mb; mb=0.0; c.b[i][j]=mc+log10(1+pow(10,ma)); } } return c;}node2 ans2,a2;void init2()//初始化{ memset(ans2.b,0,sizeof(ans2.b)); memset(a2.b,0,sizeof(a2.b)); ans2.b[0][0]=-1.0; ans2.b[1][0]=-1.0;ans2.b[1][1]=-1.0; a2.b[1][1]=-1.0;}void pow2(int s)//快速幂{ init2(); while(s) { if(s%2) ans2=ans2 * a2; a2= a2 * a2; s=s>>1; }}struct node//计算后四位的矩阵{ int a[5][5];};node operator *(node a,node b){ node c; memset(c.a,0,sizeof(c.a)); for(int i=0; i<2; i++) for(int j=0; j<2; j++) { for(int k=0; k<2; k++) c.a[i][j]+=a.a[i][k]*b.a[k][j]; c.a[i][j]%=10000; } return c;}node ans1,a1;void init1(){ memset(ans1.a,0,sizeof(ans1.a)); memset(a1.a,0,sizeof(a1.a)); ans1.a[0][1]=1; a1.a[0][0]=1;a1.a[0][1]=1; a1.a[1][0]=1;}void pow1(int s){ init1(); while(s) { if(s%2) ans1=ans1*a1; a1=a1*a1; s=s>>1; }}int main(){ f[0]=0; f[1]=1; for(int i=2;i<=39;i++) f[i]=f[i-1]+f[i-2]; int k; while(~scanf("%d",&k)) { if(k<=39) printf("%d\n",f[k]); else { pow2(k); double p=ans2.b[0][0]; p=p-(int)p; p=pow(10,p); printf("%d...",(int)(p*1000)); pow1(k); printf("%04d\n",ans1.a[0][0]); } }}
- HDU 3117 由n^k的前4位,推出(斐波那契)矩阵^k的前四位
- hdu 1568求斐波那契数的前4位 && hdu3117矩阵快速幂
- UVa 11029 - Leading and Trailing 数学题(求n^k的前N位和后N位)
- Fibonacci 斐波那契数列(求第n项值的前4位数字)
- 已知一个整数n,求n^n的前k位
- 求f(k)=k^k(k=1...n)的前n项和
- 求n^k的前3位和后3位
- HDU1568 Fibonacci 斐波那契的前4位
- [斐波那契前n位 数学技巧] HDU 1568 Fibonacci
- 怎样k^N的最高位
- UVA 11029 Leading and Trailing(大数n^k的前x位高精度问题)(好题)
- UVa 11029 - Leading and Trailing 求n^k的前3位
- 输出斐波那契数列的前n项
- 斐波那契数列的前n项
- HDU 5884 k叉的哈夫曼 O(n)构造
- HDU 1568-Fibonacci(整数的前n位)
- 求n^k的前三位数和后三位数
- 输出前n个数组合成的第k个数
- 小白实验室-Java:注解
- Hibernate学习总结(三)
- 617. Merge Two Binary Trees
- ES6开发环境配置
- Ubuntu搭建邮件服务器
- HDU 3117 由n^k的前4位,推出(斐波那契)矩阵^k的前四位
- crond和crontab
- C++指针
- C++搜索与回溯算法之Lake Counting(数湖)
- PAT乙级 1066. 图像过滤(15)
- 能不用电视显示器接电脑就不用电视显示器接电脑
- git常用命令
- 论思想之造化
- leetcode(1)_Two Sum