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

题目:给定一个长度为40的数字,问其是否在前100000项fibonacci数的前缀

因为是前缀,容易想到字典树,同时因为数字的长度只有40,所以我们只要把fib数的前40位加入字典树即可。这里主要讨论下怎么得到fib数的前40位。

首先,因为没可能每一项的fib都求出来的了。空间都存不下来。所以,只能够缩小规模,有个明显的道理,用每个fib的前60项相加取前40即可。为什么呢?因为没有后效性,后面的项相加不会影响到前40项。就是你有40--60这些项来缓冲就够了,这些才是主要的进位项。后面的相当于无穷小,影响不大。可以理解成误差把。。。两个浮点数差值不超过eps就相等,一样的意思。

所以,我们要做的是:

如果F1 和 F2 是大于40位数字的,那么我们就取前60位相加就好了,但是有一个很坑爹很坑爹的地方,就是:假如现在是取前3位吧,然后我取4位来消除误差(其实是不够的,我只是举例子)一个数字是123456,另一个是7894561,这样的话,大家都大于4位啊,但是位数不同啊,你没理由取1234+7894吧,这样就直接wa啊。123456 + 7894561 = 8018017.所以应该是取7894和123相加啊。

那么怎么知道那个是大那个是小啊,什么时候多一位什么时候位数没关系啊?,经测试,如果你一直取相同位数相加的话,会在284项时GG,不要问我怎么知道的,我找了一天的数据。

首先要知道的是,肯定是F2先到达60项的,因为F2绝对比F1大嘛。。所以,当F2到达61项的时候,我就要把F2的第61项砍掉,这个时候F2的项数变小了,同时,如果F1比F2少一位的,就是60位,会发生刚才那种坑爹的情况,所以这个时候也要把F1的第60位砍掉。不然就发生刚才的情况

那么如果都是61位呢?没事,F2都砍了,F1也砍。不然F1就比F2多啦。

所以是 if (lenstr2 > dd)  str1[lenstr1] = str2[lenstr2]=‘\0‘;//F2先到达,要砍同时砍   dd=60

注意不能分开判断

// if (lenstr1>dd) str1[lenstr1]=‘\0‘;
// if (lenstr2>dd) str2[lenstr2]=‘\0‘; /gg的

为什么呢?很简单,因为F1=60(不大于dd),而F2=61(大于dd)砍掉了一位,这样就不行了,坑爹情况出现

然后说一下后效性,F1+F2 = F3,这个F3有61位怎么办?一样,循环,然后继续砍掉,,所以我一直保持了F2在60位(因为每次相加最多能增加一位,而增加后,我又砍掉了。不增加,我不砍就是了。),而F1,可能59位(坑爹情况),可能60位。

好累,这题想了好久。

抓住一点的就是,当他超过60位,要砍项,str[lenstr]=‘\0‘;把str[lenstr]这一项砍掉了。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;

#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
const int maxn=1e6;
const int N=10;//26个小写字母
struct node
{
    //int flag;//标记以这个字母结尾为一个单词
    int count;//标记以这个字母结尾为一个前缀
    struct node *pNext[N];//26枚字符指针
} tree[maxn*N]; //大小通常设为 单词个数*单词长度
int t;//表明现在用到了那个节点
struct node *create ()
{
    //需要新开一个字符节点,就是有abc这样,插入abd,则d需要新开节点
    struct node *p=&tree[t++];
    //p->flag=0;    //初始值为0,不是整个单词
    p->count=1;    //前缀是必须的,本身就是一个了
    for (int i=0; i<N; i++)
    {
        p->pNext[i]=NULL;//初始化指针
    }
    return p;
}
void insert (struct node **T,char str[],int cnt)
{
    struct node *p = *T;
    if (p==NULL)
    {
        p=*T=create();
    }
//    int lenstr = strlen
    for (int i=1; str[i] && i <= 42; ++i)
    {
        int id = str[i]-‘0‘;
        if (!p->pNext[id])
        {
            p->pNext[id]=create();
            p->pNext[id]->count = cnt;
        }
        p = p->pNext[id];
    }
    if (!p->count) p->count = cnt;
}
int find (struct node *T,char str[])
{
    if (T==NULL) return -1;
    struct node *p = T;
    for (int i=1; str[i]; ++i)
    {
        int id = str[i]-‘0‘;
        if (!p->pNext[id]) return -1;
        p = p->pNext[id];
    }
    return p->count;
}

int b[300]= {0}; //maxn关键,栈分配,系统帮你释放,要时间,不乱开
void bigadd (char str1[],char str2[],char str3[])
{
    int len1=strlen(str1+1);
    int len2=strlen(str2+1);
    //int b[300]= {0}; //maxn关键,栈分配,系统帮你释放,要时间,不乱开
    memset(b,0,sizeof (b));
    int i=len1;
    int j=len2;
    int h=1;
    while (i>=1&&j>=1)
    {
        b[h++]=str1[i--]-‘0‘+str2[j--]-‘0‘;
    }
    while (i>=1)
    {
        b[h++]=str1[i--]-‘0‘;
    }
    while (j>=1)
    {
        b[h++]=str2[j--]-‘0‘;
    }
    for (int i=1; i<h; i++)
    {
        if (b[i]>=10)
        {
            b[i+1]++;
            b[i]-=10;
        }
    }
    if (!b[h])
    {
        h--;
    }
    int t=h;
    for (int i=1; i<=h; i++)
    {
        str3[t--]=b[i]+‘0‘;
    }
    str3[h+1]=‘\0‘; //一定要手动结束
    return ;
}
struct node *T = NULL;
char str1[1000],str2[1000],ans[1000];
void init ()
{
    str1[1]=‘1‘;
    str1[2]=‘\0‘;
    insert(&T,str1,1);
    str2[1]=‘1‘;
    str2[2]=‘\0‘;
    insert(&T,str2,2);
    int lenstr1=1,lenstr2=1;
    int dd=60;
    for (int i=2; i<100000; ++i)
    {
        lenstr1 = strlen(str1+1);
        lenstr2 = strlen(str2+1);
//        if (lenstr1>=dd) str1[lenstr1]=‘\0‘;
//        if (lenstr2>=dd) str2[lenstr2]=‘\0‘;  /gg的
        if (lenstr2 > dd)
        {
            str1[lenstr1] = str2[lenstr2]=‘\0‘;//砍项
            //str1[dd+1] = str2[dd+1] = ‘\0‘;
            //考虑下为什么不行,因为一直都是60项了
        }
//        printf ("%s\n%s\n",str1+1,str2+1);
//        lenstr1 = strlen(str1+1);
//        lenstr2 = strlen(str2+1);
//        printf ("%d %d\n",lenstr1,lenstr2);
        bigadd(str1,str2,ans);
        insert(&T,ans,i+1);
        strcpy(str1+1,str2+1);
        strcpy(str2+1,ans+1);
//
//        printf ("\n");
//        printf ("%s [%d]\n",ans+1,i);
//        printf ("\n");
    }

    return ;
}
int gg;
void work ()
{
    scanf("%s",str1+1);
    int t=find(T,str1);

    if (t!=-1) --t;
    printf ("Case #%d: %d\n",++gg,t);
    return ;
}
int main()
{
#ifdef local
    freopen("data.txt","r",stdin);
#endif
    init();
    int t;
    scanf("%d",&t);
    while (t--) work();
    return 0;
}

时间: 2024-10-01 07:37:39

UVA - 12333 Revenge of Fibonacci 高精度加法 + 字典树的相关文章

HDOJ 题目1789 Revenge of Fibonacci(大数, 字典树)

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

UVA 11732 strcmp() Anyone? (压缩版字典树)

题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2832 按照正常的字典树建树会MLE 所以需要采用树的压缩算法来建树 #include <cstdio> #include <iostream> #include <cstring> #define maxn 4000010 #define ma

fibonacci高精度加法

A Fibonacci sequence is calculated by adding the previous two members the sequence, with the first two members being both 1. F(1) = 1, F(2) = 1, F(3) = 1,F(4) = 1, F(n>4) = F(n - 1) + F(n-2) + F(n-3) + F(n-4) Your task is to take a number as input, a

UVA-12333 Revenge of Fibonacci(竖式加法模拟 &amp; 字典树)

题目: 给出一个斐波那契数字的前缀,问第一个有这个前缀的数字在斐波那契数列中是第几个. 思路: 紫书提示:本题有一定效率要求.如果高精度代码比较慢,可能会超时. 利用滚动数组和竖式加法来模拟斐波那契相加的过程,在这个过程中每得出一个斐波那契数字就用字典树存一下. PS:在滚动数组中存的斐波那契数字是逆序存储的. 代码: #include <bits/stdc++.h> #define inf 0x3f3f3f3f #define MAX 1e9; #define FRE() freopen(&

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

HDU 4099 Revenge of Fibonacci Trie+高精度

Revenge of Fibonacci Problem Description The well-known Fibonacci sequence is defined as following: Here we regard n as the index of the Fibonacci number F(n).  This sequence has been studied since the publication of Fibonacci's book Liber Abaci. So

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的进位不会形成递推

hrbust 1209/hdu 4099 Revenge of Fibonacci【字典树+大数】

Revenge of Fibonacci Time Limit: 5000 MS Memory Limit: 204800 K Total Submit: 37(24 users) Total Accepted: 18(17 users) Rating:  Special Judge: No Description The well-known Fibonacci sequence is defined as following: F(0) = F(1) = 1 F(n) = F(n - 1)