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;
}
View Code

 

posted on 2016-08-23 22:53  stupid_one  阅读(350)  评论(0编辑  收藏  举报

导航