hdu 1316 How Many Fibs?(大数,二分)

思路:因为数据规模达到了10^100,所以必须要用大数, 直接用java的大数应该能比较快的A掉,这里我用的是C++ 模拟。

第一步,将斐波那契数 打表,因为增长速度很快,10^100级别的斐波那契数 大概在数列的500左右的样子,

第二步,对输入数据a,b分别在表中二分出其大概所在的位置,这个二分要注意点,因为你要据此计算出答案来,所以必须自己考虑清楚。因为斐波那契数列的个数不多,也可以直接一个一个的看是否在[a,b]区间。

最后,输出个数即可。


#include <iostream>
#include <cstring>
using namespace std;

const int MAX_ = 1001;

int f[MAX_][MAX_];
int M;

void add(int s1[],int s2[],int s3[]) {
    int i, *m, maxi, mini;
    if(s1[0] > s2[0]) {
        maxi = s1[0], mini = s2[0], m = s1;
    } else {
        maxi = s2[0], mini = s1[0], m = s2;
    }
    for(i = 1; i <= mini; ++i) {
        int t = s1[i] + s2[i] + s3[i];
        s3[i] = t%10;
        s3[i+1] += t/10;
    }
    for(; i <= maxi; ++i) {
        int t = s3[i] + m[i];
        s3[i] = t%10;
        s3[i+1] += t/10;
    }
    if(s3[i] > 0)s3[0] = i;
    else s3[0] = maxi;
}

void fun() {
    memset(f,0,sizeof(f));
    f[1][0] = 1;
    f[1][1] = 1;
    f[2][0] = 1;
    f[2][1] = 2;
    for(M = 3; ; ++M) {
        add(f[M-1],f[M-2],f[M]);
        if(f[M][0] >= 101){break;}
    }
}

int judge(int a[], int b[]) {
    if(a[0] > b[0])return 1;
    else if(a[0] < b[0])return -1;
    int maxi = a[0];
    for(int i = a[0]; i > 0; --i) {
        if(a[i] > b[i])return 1;//a>b
        else if(a[i] < b[i])return -1;//a<b
    }
    return 0;
}

int find(int key[], int p) {
    int l, r, mid;
    l = 1, r = M;
    while(l < r) {
        mid = (l + r)/2;
        int tmp = judge(key,f[mid]);
        if(tmp == 0)return mid;

        if(r - l == 1) {
            int t1,t2;
            t1 = judge(key,f[r]);
            t2 = judge(key,f[l]);
            if(t1 == 0)return r;
            else if(t2 == 0)return l;
            if(t1 == -1 && t2 == 1) {//要查的数,在最小的斐波那契数和最大的斐波那契数之间
                if(p == 1) {
                    return r;
                } else return l;
            }
            if(t2 == -1){//不在最大最小之间。
                if(p == 1)return l;
                else return l - 1;//这样的返回设置就是为了统一一个输出公式. 可以根据自己的想法另行设置.
            }
            if(t1 == 1){
                if(p == 1)return r + 1;
                else return r;
            }

        }
        if(tmp == -1) r = mid;
        else if(tmp == 1) l = mid;
    }
}

int main() {
    int n, x[MAX_], y[MAX_], i, j;
    string s1,s2;
    fun();
    while(1) {
        cin>>s1>>s2;
        if(s1[0] == '0' &&s2[0] == '0')break;
        if(s2[0] == '-') {
            cout<<"0"<<endl;
            continue;
        } else if(s1[0] == '-') {
            j = 1;
        } else j = 0;

        if(j == 1) {
            memset(x,0,sizeof(x));
            x[0] = 1;
        } else {
            int len = s1.length();
            for(i = 0; i < len; ++i) {
                x[len - i] = s1[i] - '0';
            }
            x[0] = s1.length();
        }

        int len = s2.length();
        for(i = 0; i < len; ++i) {
            y[len - i] = s2[i] - '0';
        }
        y[0] = s2.length();
        /*int ans=0;
        for(i = 1; i <= M; ++i){
            if(judge(f[i],y) == 1)break;
            if(judge(f[i],x) != -1)ans++;
        }
        cout<<ans<<endl;*/
        if((judge(x,f[M]) == 1 )|| (judge(y,f[1]) == -1))cout<<"0"<<endl;
        else {
            cout<<find(y,0) - find(x,1) + 1<<endl;
        }
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值