zoukankan      html  css  js  c++  java
  • UVA

    /*
      参考:
      http://www.cnblogs.com/kunsoft/p/5312726.html
      
      收获:
      1. 了解了字典树,可参考几个博客:
      http://blog.csdn.net/u012469987/article/details/43874051
      http://blog.csdn.net/u011787119/article/details/46991691
      
      2.复习了常量指针和指向常量的指针
      http://blog.csdn.net/luoweifu/article/details/45600415
      
      3.复习了之前在看《挑战》时,只是略有了解的滚动数组
      http://blog.csdn.net/u012577123/article/details/39211361
      滚动数组最大的意义,在于缩减空间方面,对时间的影响不大
      
      说明:
      4.
      关于 if(e - s > 50)  ++s; 这句代码,一开始我一直不理解原因,也不明白为什么要取50,后来查阅了有关题解,才明白过来
      因为要求精确到前40位,为了避免进位的误差,所以我们计算的时候,肯定要比40算的多一些(否则,如果真的取40,可能会有一些进位误差没有考虑到,例如有某个F数组的元素,算出来有进位,但是没有进行进位处理,如果这个错误的位置,恰好在我们需要的前40的精度里,那么就会WA了)
      
      最后试验的结果时, e - s至少为49,当然,取200什么的也没问题,这个主要是代表了一个精度,让我们知道,我们求得的斐波拉契数列,大概有前多少位的范围,是精确可靠,可以相信的,所以往多了取当然没问题,但是不能取少了,所以最合适的是50、60的样子
      
      另附上其他博客里的一些解释
      
      4.1. 因为只是需要前40位,而且fibonacci数列上升速度很快, 所以我们保留60位的精度就足够了。
      http://www.cnblogs.com/Jadon97/p/6922619.html
      
      4.2. 因为只要前40位数字。所以在加的时候长度大于50左右就截掉个位上的,保留高位。
      (这是我觉得最清楚而言简意赅的解释了,因为斐波拉契数可能会有很多位,所以我们要截断,可是只截断40位,可能有未处理的进位导致WA,所以我们截断前50位左右)
      http://www.cnblogs.com/kuangbin/archive/2012/09/06/2673897.html
      
      4.3.我们可以把斐波那契数列精确到50多位,然后只存40位即可,这样就防止进位的误差。在斐波那契数列加法过程中,我们只把它的前50多位进行相加,不然存不下。
      http://blog.csdn.net/u012965373/article/details/40636371
      
    */



    #include <bits/stdc++.h>
    using namespace std;
    
    struct Node
    {
    	int id;
    	Node* next[10];
    	Node()
    	{
    		id = -1;
    		memset(next, 0, sizeof(next));
    	}
    };
    
    char Fib[50], In[50];
    int F[2][1024000];
    Node *const root = new Node();
    
    void add_node (char* str, int id)
    {
    	Node *u = root;
    	for (int i = 0, len = (int)strlen(str); i < len && i <= 40; i++)
    	{
    		int v = str[i] - '0';
    		if (!u->next[v])
    		u->next[v] = new Node();
    		
    		u = u->next[v];
    		if (u->id == -1)
    		u->id = id; 
    		//同一个长度n的斐波拉契数,截断为前1~i(1 <= i <= n)位以后,所有的截断方式,都具有相同的序号,表示以该字符串开头的斐波拉契数,对应的序号都是id
    	}	
    }
    
    int query(char* str)
    {
    	Node *u = root;
    	 // 在树上顺序搜索str的每一个字符
    	for (size_t i = 0, len = strlen(str); i < len; i++)
    	{
    		u = u->next[str[i] - '0'];
    		// 若为空集,表示不存以此为前缀的斐波拉契序号 
    		if (!u) return -1;
    	}
    	// 返回以该信息为前缀的斐波拉契序号 
    	return u->id;
    }
    
    void init()
    {
        memset(F, 0, sizeof(F));
        F[0][0] = F[1][0] = 1;
        int s = 0, e = 1;
        add_node((char *)"1", 0);
        add_node((char *)"1", 1);
        for(int i = 2; i < 100000; ++i)
    	{
            int p = i%2, q = (i+1)%2;
            for(int j = s; j < e; ++j)
                F[p][j] = F[p][j] + F[q][j];
            for(int j = s; j < e; ++j)
                if(F[p][j]>=10)
    			{
                     F[p][j] %= 10;
                     F[p][j+1] += 1;
                }
            if(F[p][e])  ++e;
            if(e - s > 50)  ++s;
            int r = e - 1, cnt = 0;
            memset(Fib, 0, sizeof(Fib));
            while(r >= 0 && cnt<40) //<40的限定,是因为输入不超过40个数字,因此初始化时,我们也只是取前40个数,若位数太多,有可能超过int的范围,导致运行错误(如果不对cnt做限定,则将RE)
                Fib[cnt++] = F[p][r--] + '0';
            add_node(Fib, i);
        }
    }
    
    int main()
    {
    	cin.tie(0);
    	cin.sync_with_stdio(false);
    	init();
    	int t;
    	cin >> t;
    	for (int i = 1; i <= t; i++)
    	{
    		cin >> In;
    		cout << "Case #" << i << ": " << query(In) << endl;
    	}
    	
    	return 0;
    }


  • 相关阅读:
    linux 端口号、进程id、杀进程、查询tcp的连接(各种状态的)
    泛型---(静态方法中为什么不能引用类级别的参数)
    net.sf.json------json解析
    微信调用40001
    第十五章 泛型
    CentOS7下安装Nodejs
    CentOS7下安装RabbitMQ
    Centos7搭建FTP服务器
    Windows10下mysql-5.7.19免安装版配置
    Windows下dubbo环境搭建及初步使用
  • 原文地址:https://www.cnblogs.com/mofushaohua/p/7789410.html
Copyright © 2011-2022 走看看