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\n",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\n",ans==-1 ? -1:ans-1);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/sykline/p/10285500.html

时间: 2024-10-11 06:51:45

UVA-12333 Revenge of Fibonacci(竖式加法模拟 & 字典树)的相关文章

UVA - 12333 Revenge of Fibonacci 高精度加法 + 字典树

题目:给定一个长度为40的数字,问其是否在前100000项fibonacci数的前缀 因为是前缀,容易想到字典树,同时因为数字的长度只有40,所以我们只要把fib数的前40位加入字典树即可.这里主要讨论下怎么得到fib数的前40位. 首先,因为没可能每一项的fib都求出来的了.空间都存不下来.所以,只能够缩小规模,有个明显的道理,用每个fib的前60项相加取前40即可.为什么呢?因为没有后效性,后面的项相加不会影响到前40项.就是你有40--60这些项来缓冲就够了,这些才是主要的进位项.后面的相

N分之一 竖式除法模拟

N分之一 Description Alice越来越痴迷于数学问题了.一天,爸爸出了个数学题想难倒她,让她求1 / n. 可怜的Alice只有一岁零九个月,回答不上来 ~~~~(>_<)~~~~  于是她求你编个程序帮她算出来. Input 第一行是一个整数T,表示测试组数.接下来T行,每行一个整数 n ( 1 ≤ |n| ≤ 105 ). Output 以实数形式输出1/n .如果是无限循环小数的,只需输出第一个循环节. Sample Input 4237168 Sample Output 0

UVA-12333 Revenge of Fibonacci

题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3755 题目大意: 意思不难理解,就是找到以某个字符串为前缀的最小的斐波拉契数列,并输出是第几个斐波拉契数.找不到就输出-1: 思路:大数加法,字典树. ps:通过这道题接触到了大数加法.(虽然之前在刘汝佳的那本算法书里看到过阶乘的,但当时匆匆略过了) 该题是多组输入,我们就对斐波

hdu 4099 Revenge of Fibonacci Trie树与模拟数位加法

Revenge of Fibonacci 题意:给定fibonacci数列的前100000项的前n位(n<=40);问你这是fibonacci数列第几项的前缀?如若不在前100000项范围内,输出-1: 思路:直接使用数组模拟加法,再用Trie树插入查找即可:但是一般使用new Trie()的代码都是MLE的.反而我之前写的,直接得到数组大小的maxnode版本的内存可以接受:并且还有一点就是前40位的精度问题:由于是自己计算出来的finboncci数列,并不是系统给的,所以1的进位不会形成递推

HDU4099 Revenge of Fibonacci(高精度+Trie)

Revenge of Fibonacci Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 204800/204800 K (Java/Others) Total Submission(s): 2582    Accepted Submission(s): 647 Problem Description The well-known Fibonacci sequence is defined as following: Here w

hdu 4099 Revenge of Fibonacci(字典树)

Revenge of Fibonacci Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 204800/204800 K (Java/Others) Total Submission(s): 2355    Accepted Submission(s): 587 Problem Description The well-known Fibonacci sequence is defined as following: Here w

数学竖式排版中不为人知的技巧

在使用mathtype的过程中,难免会遇到一些不知道怎么操作的情况,这个时候我们就需要去找一些教程来学习一下.数学数式一般涉及到三种类型,即算术“加.减.乘.除”的竖式,代数多式加法.乘法.除法的排法,开平方竖式的排法.本教程将介绍数学竖式排版的一些技巧. (1)算术“加.减.乘.除”的竖式,其整数.小数位一般在4位以内,数码与数码之间一律疏排,2位数空对开,3位.4位数空三分.数式一般用三号.四号或小四号的正体数码字排版.乘法和除法竖式均为多层重叠.如下图所示: (2)代数多项式加法.乘法.除

大数运算——字符串操作结合“竖式计算“思想的实现

总体原则: 字符串转整形数组,然后按照“竖式计算”的思想,按位(对于数组来说,就是对应位置的元素)进行运算,同时处理进位.退位.最后将整形数组转换为字符串输出. Ps:1.字符串转整形,本文采取逆序存储的方式,即将字符串的低位(大数的高位)放置到整形数组的高位. 2.本文提供的四个四则运算方法,所有的输入值(大数)必须为正整数. 一.加法 加法运算遵循从低位到高位运算的法则.将字符串转换为整形数组后,两数组对应元素相加,结果存储至结果数组的相应元素位置.同时对相加后的元素进行整除和取余运算(整除

HDU 4099 Revenge of Fibonacci

Revenge of Fibonacci Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 204800/204800 K (Java/Others) Total Submission(s): 2027    Accepted Submission(s): 475 Problem Description The well-known Fibonacci sequence is defined as following: Here w