Uva 12333 Revenge of Fibonacci (字典树 + 大数加法运算)

大体题意:

告诉你一个长度不超过40的字符串,要求找出最小的斐波那契数列的位置 使得这个字符串是那个斐波那契数的前缀!

如果100000项以内的斐波那契数列没有它,输出-1!

思路:

思路很明显:

直接先预处理出来1~100000以内的斐波那契数列来, 只用到了高精度加法,拿字符串模拟即可!

然后求出一项来,插入到字典树中,字典树每一个节点的权值代表着以他为终点的前缀  是 斐波那契数的哪一项!不断取最小值即可!


仅供参考吧,  代码很慢!  5400多ms 才过的!

想了想 慢就慢在算高精度加法上了!

详细见代码:

=============================================

重新更新一下这篇博客!

这个题目也是HDU 4099 的题目,我的时间是5400ms 显然过不了  HDU 的5s限制! 能过也是爆内存!

有一个优化  它算的只是前40位,  数据范围是10W项, 它的位数也差不多10w位左右! 我们只保存  前50位即可!超出的部分割掉即可!  这样无论在速度还是内存上都优化了不少!

详细见代码:


#include <cstdio>
#include <cstring>
#include <algorithm>
#define min(x,y) (x) > (y) ? (y) : (x)
#define max(x,y) (x) > (y) ? (x) : (y)
using namespace std;
const int maxn = 50 + 7;
const int inf = 0x3f3f3f3f;
char q[41];
char s1[maxn], s2[maxn], s3[maxn], tmp[maxn];
struct Tree{
    int v;
    Tree* next[10];
    Tree(int v = inf):v(v){ for (int i = 0; i < 10; ++i) next[i] = NULL; }
}*root;
void insert(char* s,int k) {
    Tree* cur = root;
    for (int i = 0; s[i] && i < 41; ++i){
        int id = s[i] - 48;
        if (cur -> next[id] == NULL){
            cur -> next[id] = new Tree();
        }
        cur = cur -> next[id];
        cur->v = min(cur->v,k);
    }
}
int query(char* s) {
    Tree* cur = root;
    for (int i = 0; s[i]; ++i){
        int id = s[i] - 48;
        if (cur->next[id] == NULL)return -1;
        cur = cur->next[id];
    }
    return cur->v;
}
void init(){
    root = new Tree();
    s1[0] = s2[0] = '1';
    s1[1] = s2[1] = 0;
    insert(s1,0);
    insert(s2,1);
    for (int k = 2; k < 100000; ++k){
        int len1 = strlen(s1);
        int len2 = strlen(s2);
        if (len2 > 50){
            s2[--len2] = 0;
            s1[--len1] = 0;
        }
        int flag = 0, i, j;
        i = len1-1,j = len2-1;
        int p = max(i,j);
        s3[p+1]=0;
        while(i >= 0 || j >= 0){
            int t = flag;
            if (~i) t += s1[i] - 48;
            if (~j) t += s2[j] - 48;
            s3[p] = t%10+48;
            if (t > 9) flag = 1;
            else flag = 0;
            if (~i)--i;
            if (~j)--j;
            --p;
        }
        int ps = 0;
        if (flag){
            tmp[ps++] = flag + 48;
        }
        tmp[ps] = 0;
        strcat(tmp,s3);
        insert(tmp,k);
        strcpy(s1,s2); strcpy(s2,tmp);
    }
}
void Free(Tree* ro){
    if (ro == NULL) return;
    for (int i = 0; i < 10; ++i){
        if (ro->next[i] != NULL) Free(ro->next[i]);
    }
//    ro = NULL;
    free(ro);
}
int main(){
    init();
    int T,ks=0;
    scanf("%d",&T);
    while(T--){
        int n;
        scanf("%s",&q);
        printf("Case #%d: %d\n",++ks,query(q));
    }
    Free(root);
    return 0;
}

===============================

以下为 5400ms 代码:


#include <cstdio>
#include <cstring>
#include <algorithm>
#define min(x,y) (x) > (y) ? (y) : (x)
#define max(x,y) (x) > (y) ? (x) : (y)
using namespace std;
const int maxn = 100000 + 7;
const int inf = 0x3f3f3f3f;
char q[45];
char s1[maxn], s2[maxn], s3[maxn], tmp[maxn];
struct Tree{
    int v;
    Tree* next[10];
    Tree(int v = inf):v(v){ for (int i = 0; i < 10; ++i) next[i] = NULL; }
}*root;
void insert(char* s,int k) {
    Tree* cur = root;
    int cnt = 0;
    for (int i = 0; s[i] && cnt < 50; ++cnt,++i){
        int id = s[i] - 48;
        if (cur -> next[id] == NULL){
            cur -> next[id] = new Tree();
        }
        cur = cur -> next[id];
        cur->v = min(cur->v,k);
    }
}
int query(char* s) {
    Tree* cur = root;
    for (int i = 0; s[i]; ++i){
        int id = s[i] - 48;
        if (cur->next[id] == NULL)return -1;
        cur = cur->next[id];
    }
    return cur->v;
}
void init(){
    root = new Tree();
    s1[0] = s2[0] = '1';
    s1[1] = s2[1] = 0;
    insert(s1,0);
    insert(s2,1);
    for (int k = 2; k < 100000; ++k){
        int len1 = strlen(s1);
        int len2 = strlen(s2);
        int flag = 0;
        int i,j;
        i = len1-1,j = len2-1;

        int p = max(i,j);
        s3[p+1]=0;
        int way = (k & 1) ? 1 : 0;
        while(i >= 0 || j >= 0){
            int t = flag;
            if (~i) t += s1[i] - 48;
            if (~j) t += s2[j] - 48;
            s3[p] = t%10+48;
            if (t > 9) flag = 1;
            else flag = 0;
            if (~i)--i;
            if (~j)--j;
            --p;
        }
        int ps = 0;
        if (flag){
            if (way) s2[ps++] = flag + 48;
            else s1[ps++] = flag+48;
        }
        if (way){
            s2[ps] = 0;
            strcat(s2,s3);
            insert(s2,k);
        }
        else {
            s1[ps] = 0;
            strcat(s1,s3);
            insert(s1,k);
        }

    }
}
int main(){
    init();
    int T,ks=0;
    scanf("%d",&T);
    while(T--){
        int n;
        scanf("%s",&q);
        printf("Case #%d: %d\n",++ks,query(q));
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值