zoukankan      html  css  js  c++  java
  • UVA-12333 Revenge of Fibonacci(竖式加法模拟 & 字典树)

    题目:

    给出一个斐波那契数字的前缀,问第一个有这个前缀的数字在斐波那契数列中是第几个。

    思路:

    紫书提示:本题有一定效率要求。如果高精度代码比较慢,可能会超时。

    利用滚动数组和竖式加法来模拟斐波那契相加的过程,在这个过程中每得出一个斐波那契数字就用字典树存一下。

    PS:在滚动数组中存的斐波那契数字是逆序存储的。

    代码:

    #include <bits/stdc++.h>
    #define inf 0x3f3f3f3f
    #define MAX 1e9;
    #define FRE() freopen("in.txt","r",stdin)
    #define FRO() freopen("out.txt","w",stdout)
    using namespace std;
    typedef long long ll;
    const int maxn = 4000010;
    struct Node {
        int next[10];
        int id;
        Node() {
            for(int i = 0; i<10; i++) {
                next[i] = -1;
            }
            id = -1;
        }
    };
    Node trie[maxn];
    int tot = 0;
    //Node root = trie[tot++];
    
    int idx(char ch) {return ch-'0';}
    
    void Insert(char* str, int id) {//字典树插入
    //    int u = 0;
    //    for(int i = 0; i<strlen(str); i++) {
    //        int v = idx(str[i]);//获取字符串当前位置的数字
    //        if(trie[u].next[v]==-1) { //如果这个位置是不存在的
    //            trie[u].next[v] = tot;
    //            u = tot++;
    //        } else { //如果这个位置是存在的
    //            u = trie[u].next[v];
    //        }
    //        if(trie[u].id==-1) {
    //            trie[u].id = id;
    //        }
    //    }
        int u = 0;
        for(int i = 0; i<strlen(str); i++){
            int v = idx(str[i]);
            if(trie[u].next[v]==-1){//如果这个位置不存在
                trie[u].next[v] = tot++;
            }
            u = trie[u].next[v];//结点往下走
            if(trie[u].id==-1){//保存这个斐波那契数字的id
                trie[u].id = id;
            }
        }
    }
    
    int Query(char* str) {
        int u = 0;
        for(int i = 0; i<strlen(str); i++) {
            int v = idx(str[i]);
            if(trie[u].next[v]==-1) { //说明这个前缀不会出现
                return -1;
            }
            u = trie[u].next[v];
        }
        return trie[u].id;
    }
    
    
    int fib[2][maxn];
    int main() {
        FRE();
        int s=0,l=1;
        char f[55];
        Insert("1",1);
        fib[1][0] = 1;
        fib[0][0] = 0;
        for(int i=2; i<100000; i++) {
            int a=i%2, b=(i+1)%2;//滚动数组,可以手动跑两组斐波那契数字的相加就可以理解了
            for(int k=s; k<l; k++) {
                fib[a][k] = fib[a][k] + fib[b][k];
                if(fib[a][k]>=10) { //这位相加可以进位时
                    fib[a][k+1]++;//下一位加一
                    fib[a][k] -= 10;//这一位减掉进位的10
                    if(k==l-1) { //最后一个进位让l加一
                        l++;
                    }
                }
            }
            if(l-s>50) { //数组中是倒着存这个数的,l-1表示个位开始,s表示最高位
                s++;
            }
            int cnt=0;
            for(int k=l-1; k>=s&&cnt<40; k--){//根据题目提示,只选取前40位即可
                f[cnt++] = fib[a][k]+'0';
            }
    //        if(i==10)
    //            printf("%s
    ",f);
            Insert(f,i);
            memset(f,0,sizeof(f));
        }
        //cout<<"GG"<<endl;
        char str[55];
        int n;
        scanf("%d",&n);
        for(int i=0; i<n; i++){
            scanf("%s",str);
            printf("Case #%d: ",i+1);
            int ans = Query(str);
            printf("%d
    ",ans==-1 ? -1:ans-1);
        }
        return 0;
    }
  • 相关阅读:
    编码问题
    apache 2.4 httpd 2.4.6 反向代理后端的服务为HTTPS https 基于centos7
    ucore系统 eclipse-cdt实验环境准备
    openshift v1.5 不能登录system:admin 问题
    filebeat v6.3 如何增加ip 字段
    filebeat v6.3 多行合并的步骤 多个表达式同时匹配
    如何一步步使用国内yum源一键安装openstack-ocata版本基于centos7
    windows 定时删除N天前日志脚本
    logrotate 如何执行日志按照大小切分
    virtualbox 基于nat模式搭建局域网并且和宿主机通信
  • 原文地址:https://www.cnblogs.com/sykline/p/10285500.html
Copyright © 2011-2022 走看看