/*******对读者说(哈哈如果有人看的话23333)哈哈大杰是华农的19级软件工程新手,才疏学浅但是秉着校科联的那句“主动才会有故事”还是大胆的做了一下建一个卑微博客的尝试,想法自己之后学到东西都记录一下
自己学的同时或许(我说或许啊哈哈)能帮到博友,如果有啥错误的话还请各位大佬在下面留言怼我,指出我的错误所在,我一定更改哈哈,一般记录的都是我对一个知识点或者是一个算法专题的笔记和一些在博客园里面看到写的好的大佬的一些借鉴
文章大部分都是在codeblocks里面写好了然后复制过来的,所以就有很多///***的,对你的产生困扰,深感抱歉
********/
//对自己说:坚持坚持坚持,总会有收获,主动就会有故事!
//分割线------------------------------------------------------------本文借鉴https://www.cnblogs.com/orchidzjl/p/4287027.html(原文)
/********************
菲波数
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 12716 Accepted Submission(s): 4352
f(1)=f(2)=1
f(n)=f(n-1)+f(n-2) n>=3。
计算第n项Fibonacci数值。
思路:很纯粹的高进度加法
基础板子
//一般Fibonacci数在第一千多个的时候的值其实就已经达到了一百多位了,一般就10的一百多次方了
这种高位数就自然用数组来存放也就是利用高精度加法了,然后由于是要输入一个值n,然后输出的是第
个fabonacci数的,所以就要用一个map原理
在c里面就自然的用到了二维数组来存放了,就是一维数组的下标就是这个n,然后这个一维数组的元素组成就是第
n个数了
一般遇到差不多一千多位的fabonacci数的化就要建立一个数组是a[1010][1010]
其实一千位的fabonacci数也就差不多几百位,这里建立一千多位其实是浪费的,如果是要节省空间的化还是
就建立一个大菲波数 ---【杭电-HDOJ-1715】
a[1010][500]就差不多了
int ans[1010][500]//装答案的/由于会用在高精度计算的函数里面也会在主函数里面用到的,所以就定义位全局变量就可以了
int c[500],d[500];由于只是在高精度函数里面用到这两个数组的所以最好还是不要定义位全局变量了,节省空间,装第n-1个的fabonacci和第n-2个的fabonacci的,然后两个用递归来相加,用到高精度计算了
int n,m,i,j,k;//n是记录a数组的长度的,m是记录b数组长度的,ijk是用来循环的,同样的也是在函数里面哟ing到了的,不要定义位全局了
大菲波数
2019.11.25.9.18
*****************/
代码:
/*
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
char ans[1010][500]; //优化:ans用char比用int要节省空间,然后c数组和d数组由于是要进行计算的要除以10和对10取模的所以是要定义位int
//所以就要注意在类型上的转化比如如果是char变成int的化就要-'\0'如果是int变成char的化就要+'\0'
void bigplus(char a[],char b[],int t) //这里的t表示的是第几个fabonacci数的,然后a和b其实就是递归里面用到的第n-1项和第n-2项的
{
int c[500];
int d[500];
memset(c,0,sizeof(c));memset(d,0,sizeof(d));
int n,m,i=1,j=1,k;
n=strlen(a);
m=strlen(b);
for(k=n-1;k>=0;k--) //这些就没什么好解析的了,在oj是实验题里面就有高精度计算的水题了,或者在网上差一下给高精度计算的板子就会了
//不同的是oj上面的是用到了一个e来作为余数的就是
//c[i]=(a[i]+b[i]+e)%10;
// e=(a[i]+b[i])/10;//其实用这个方法是更省了d这个数组的空间的了,不过我就是看到下面那个c[i+1]+=..这一步不同然后想积累一下别的方法才写的hah1 {
c[i++]=a[k]-'0';
}
for(k=m-1;k>=0;k--) //开始我搞错了边了了,k=n-1然后打印出来的结果就多了很多其他的符号呢
{
d[j++]=b[k]-'0';
}
k=n>m?n:m;
for(i=1;i<=k;i++)
{
c[i+1]+=(c[i]+d[i])/10;
c[i]=(c[i]+d[i])%10;
}
if(c[k+1])
k+=1;
j=0;
for(i=k;i>=1;i--)
ans[t][j++]=c[i]+'0'; }
int main()
{
memset(ans,'\0',sizeof(ans)); //由于是ans是不可以初始化为0或者是其他数组的不然之后打印的时候就会把后面的数组也打印出来了
// 所以就要对ans初始化是如何地方都是可能是中止的地方也就是要初始化为结束符了
int i,n;
ans[1][0]='1';
ans[2][0]='1'; //由于左下标(二维数组)是表示的是第几个fabonacci数的,如何由于是第一个fabonacci是1,第二个也是
// 第二个也是1,并且他们都是个位的所以就初始化,
//(如果是第七个的化就是ans[7][0]=1,ans[7][1]=3,因为第7个fabonacci就是13了)只用初始化两个足够初始递归就可以了
for(i=3;i<=1000;i++)
{
bigplus(ans[i-1],ans[i-2],i); //每次递归都是得到一个第i个的值,由于ans是一个二维数组,但是这里传递的其实是一维数组的指针
//然后用bigplus函数里面的数组a和b来接受的
}
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
printf("%s\n",ans[n]);
}
return 0;
} */
//相关的例题就是SCAUOJ里面的1143 多少个Fibonacci数
/************
1143 多少个Fibonacci数
时间限制:500MS 内存限制:65536K
提交次数:270 通过次数:16
题型: 编程题 语言: G++;GCC
Description
给你如下Fibonacci 数的定义:
F1 = 1
F2 = 2
Fn = Fn-1 + Fn-2 (n >= 3)
给你两个数a与b,现要求你计算在a与b之间(包括a、b)有多少个Fibonacci 数
输入格式
有多行,每行有两个数a、b,使用空格分隔,a <= b <= 10^100(即最大10的100次方)
最后一行为两个0
输出格式
除了最后一行,其它每一行要求输出在a与b之间的Fibonacci 数的个数,一行一个
输入样例
10 100
1234567890 9876543210
0 0
输出样例
5
4
************/
思路:这个题目和上面板子的不同其实就是给了一个范围,很多人可能会想到这种用到范围的都是用到莫队排序的
但是我觉得这里好像不用的,如果您觉得可以用到的话欢迎给我留言,咱们一起探讨一下呀哈哈(莫队主要就是add函数和move函数,在对一维数组的一些问题上面进行算法1的
但是这里不用输出值,而是要a到b中的fabonacci数有多少个的,其实就是和ab范围内的比较,还是要吧fabonacci算出来的
就可以用到上面的板子了
先打一个前1000项的fb表(大数加法),然后 a,b在表中找位置(大数比较),那么他们之间的个数就是了
就是建表,然后比较,然后输出个数即可
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char ans[][]; //还是提醒一下吧为了优化空间的话这里吧ans二维数值是初始化为了cha类型的,
void bigplus(char a[],char b[],int t)//这个高精度计算的函数和上面的板子是一样的没有变化
{
int c[],d[];
int n,m,i=,j=,k;
memset(c,,sizeof(c));
memset(d,,sizeof(d));
n=strlen(a);
m=strlen(b);
for(k=n-;k>=;k--)
c[i++]=a[k]-'';
for(k=m-;k>=;k--)
d[j++]=b[k]-'';
k=m>n?m:n;
for(int i=;i<=k;i++)
{
c[i+]+=(c[i]+d[i])/;
c[i]=(c[i]+d[i])%;
}
if(c[k+])k+=;
j=;
for(i=k;i>=;i--)
{
ans[t][j++]=c[i]+'';
}
}
/****之后就是要有一个高精度比较,肯定不可以直接用><来比较的,因为数值都被放在了数数组里面了
除非就是用c++里面的重载运算符才可以用<和>进行比较了,所以就需要吧输入的a和b这两个边界和我们已经制好的表(也就是那个ans二维数组里面存放的值进行比较
这时候就要用到另外一个比较函数了我叫他bigcmp就是高精度比较,如果两个东西经过bigcmp比较之后返回的是1
表示前一个大于后一个,然后返回的是-1表示的是两个相等的,如果是返回0的话就表示后一个大于前一个的
*****/
//这个函数的思路肯定就是先比长度嘛,用strlen,长度长的自然就大,然后如果长度一样的话再从高位一项一项的比下来哈哈
//感觉有点麻烦,不知大佬们有啥好的方法呢? int bigcmp(char a[],char b[])
{
int i,n,m;
n=strlen(a);
m=strlen(b);
if(n>m)return ;
else if(n<m)return ; //长度一样的时候就从高位开始比,输入的范围和我们ans数值的存放的数其实高位就是从0开始的了,
// 所以在bigplus函数里面最后就是要吧c数值赋给ans的时候是要倒叙的,
// 使得这个数值的最高位是存放在ans数值的0位上的,也方便了bigcmp的比较了
else
{
for(i=;i<n;i++) //因为这里n=m,所以以n或者m作为边界都是可以的
{
if(a[i]>b[i])return ;
else if(a[i]<b[i])return ;
else //如果还是相等的话就继续比较下面的数即可了
continue; }
}
return -; //如果直到最后都没有比较出来的话说明这两个数是相等的
}
int main()
{
int i,j;
char s1[],s2[]; //s1和s2数组是用来存放我们要输入的两个数(就是左右范围了)
memset(ans,'\0',sizeof(ans));
ans[][]='';
ans[][]='';
for(i=;i<=;i++)
bigplus(ans[i-],ans[i-],i);//注意:不要写成了ans[1]和ans[2]作为第一二参数了(哈哈我刚开始就写错了)
while(scanf("%s %s",s1,s2))
{
int cnt=; //计算这个范围里面有多少个fabonacci数 像这种计数器变量的话一般都是用sum或者是cnt是count的缩写,用做计数器 if(!((s1[]-'')||(s2[]-'')))break;//就是只要不是两个输入的都是0的话都是可以进行下去的,如果都是0的话就break
for(i=;i<=;i++) //循环我们刚刚制成的fabonacci表(ans数组)
{ //再提醒一下返回值,不然你肯定又翻上面看哈哈
//比较之后返回的是1表示前一个大于后一个,然后返回的是-1表示的是两个相等的,
//如果是返回0的话就表示后一个大于前一个
if(bigcmp(ans[i],s1)==-) //两个相等的话
{
cnt=; //表示的是左范围就是一个fabonacci数了,就提前的+1,然后i++就是下次就不用又比较一次了,只要出现了这个情况就break
i++;
break; }
if(bigcmp(ans[i],s1)>) //如果s1小的话
{
cnt=;
break; }
} //开始我差点也搞混了,就是for里面嵌套一个if,这个if里面有一个break的话就会直接跳出最近的那个for(别笑,我刚开始好真的傻了) for(j=i;j<=;j++) //如果左边界也是fabonacci的刚刚就把cnt设置为了1的,然后i++,就相当于已经把左边界是fabanacci数记录了,cnt=1了; if(bigcmp(ans[j],s2)<=)cnt++;
else
break; //用这个来结束
printf("%d\n",cnt);
}
return ; }