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; }
posted on 2016-08-23 22:53 stupid_one 阅读(350) 评论(0) 编辑 收藏 举报