• 有道难题练习赛 Sibonacci


    昨晚参加了有道难题的练习赛,感觉题目也都不难,参赛人数为3747人,提交次数为20000人次。但是比赛应该说很不成功,服务器非常的很卡,网络很有问题,导致大家很多题目长期刷新不出来,或者出现error页面。我的第二题就是waiting了两个多小时,最后懒得管他了,一直到今天早上发现waiting变成compile error了,真无语。不过第三道题还是做出来了,不过我感觉我的思路有些复杂。。


    /********************************************************************************************************
    有道难题练习赛 - Sibonacci

    描述:
    菲波那切数列可以用下列的式子表示:
    f(1)=1
    f(2)=1
    f(n)=f(n-1)+f(n-2) (n>=3)

    现在我们根据这个规则定义另一种数列 命名为"辛波那切数列", 它是这样定义的:
    s(x)=0 (x<0)
    s(x)=1 (0<=x<1)
    s(x)=s(x-1)+s(x-3.14) (x>=1)

    现在需要计算出s(x) MOD 1000000007的值。
    输入
    第一行有一个正整数T表示有T组测试数据。
    接下来T行,每行包含一个数x。
    其中 T<=10000, -1000.0<=x<=1000.0
    输出
    有T行,依次输出每组数据的结果。
    样例输入

    3
    -1
    0.667
    3.15

    样例输出

    0
    1
    2
    *******************************************************************************************************
    */

    /********************************************************************************************************
    解题思路:
    首先通过尝试分解发现一个规律,就是:
    例如:
    S(8.28) 
    = S(8.28 - 1) + S(8.28 - 3.14) 
    = S(8.28 - 2*1) + 2*S(8.28 - 1 - 3.14) + S(8.28 - 2*3.14)
    = S(8.28 - 3*1) + 3*S(8.28 - 2*1 - 3.14) + 3*S(8.28 - 1 - 2*3.14) + S(8.28 - 3*3.14)
    = S(8.28 - 4*1) + 4*S(8.28 - 3*1 - 3.14) + 6*S(8.28 - 2*1 - 2*3.14) + 4*S(8.28 - 1 - 3*3.14) + S(8.28 - 4*3.14)
    =....

    从系数看联想到了杨辉三角形:
      1
      1 1
      1 2 1
      1 3 3 1
      1 4 6 4 1
      1 5 10 10 5 1
      1 6 15 20 15 6 1
      1 7 21 35 35 21 7 1 

    我们就可以这样定义个杨辉三角形二维数组num[1001][1001]:
        0   1   2   3   4   5   6 .... 1000
    0   1   1   1   1   1   1   1 ....
    1   1   2   3   4   5   6
    2   1   3   6   10  15
    3   1   4   10  20 
    4   1   5   15
    5   1   6
    6   1 
    ...
    1000

    就有如下规律:
    S(x) = ......... = num[a1][b1]*S(x - a1*1 - b1*3.14) + num[a2][b2]*S(x - a2*1 - b2*3.14) + ... + num[an][bn]*S(x - an*1 - bn*3.14)
    在根据题目中所给的规律,我们就找出所有合适的ai,bi使得x - ai*1 - bi*3.14在[0, 1)之间,然后将所有的
    num[ai][bi]相加并且模除1000000007就可以了。
    *******************************************************************************************************
    */

    #include 
    <iostream>
    #include 
    <cmath>
    #include 
    <cctype>
    #include 
    <string>
    #include 
    <map>
    #include 
    <set>
    #include 
    <vector>
    #include 
    <algorithm>
    #include 
    <list>
    #include 
    <stack>
    //#include <stdlib.h>
    //#include <iomanip>

    using namespace std;

    //二维数组保存杨辉三角形
    #define NUM 1001
    int num[NUM][NUM];

    int compute(double x)
    {
        
    int res = 0, a, b, i, j;
        
    double temp;
        a 
    = (int)x;
        b 
    = x/3.14 + 1;

        
    //i表示1的个数,j表示3.14的个数
        for (j = b; j >= 0; j--)
        {
            temp 
    = x- j*3.14;
            
    if(temp >= 0)
            {
                i 
    = (int)temp;
                res 
    += num[i][j];
                
    if(res >= 1000000007)
                    res 
    %= 1000000007;
            }
        }

        
    return res;
    }

    int main()
    {
        
    int t, res;
        
    double x;
        cin 
    >> t;

        
    //杨辉三角形
        for(int i = 0; i < NUM; i++)
        {
            
    for(int j = 0; j < NUM - i; j++)
            {
                
    if(i == 0 || j == 0)
                    num[i][j] 
    = 1;
                
    else
                {
                    num[i][j] 
    = num[i-1][j] + num[i][j-1];
                    
    if(num[i][j] >= 1000000007)
                        num[i][j] 
    %= 1000000007;
                    num[j][i] 
    = num[i][j];
                }
            }
        }

        
    for (int i = 0; i < t; i++)
        {
            cin 
    >> x;
            x 
    += 0.000000001;  //防止精度损失
            if(x < 0)
                res 
    = 0;
            
    else if(x >= 0 && x < 1.0)
                res 
    = 1;
            
    else
                res 
    = compute(x);
            cout 
    << res << endl;
        }

        
    return 0;
    }

    最后结果为:

    内存: 4416kB  时间:230ms

    还有一种方法感觉很不错:

    模拟Fibonacci数列枚举的计算方法,把Sibonacci看成是:s(x) = s(x - 100) + s(x - 314)。
    因为s(x) = s(x + 0.01),所以小数点两位以后的可以忽略。这样就一共有1000*100种情况,全部枚举出来。

  • 相关阅读:
    010 排序: 冒泡 选择
    洛谷 P1540 机器翻译
    洛谷 P1011 车站
    周期串
    2019.03.29 大数据图解
    2019.03.29 算法解读
    2019.03.28 博客反省
    2019.03.27 常用的模块
    2019.03.25 git
    2019.03.25 Ajax三级联动
  • 原文地址:https://www.cnblogs.com/CCBB/p/1743414.html
Copyright © 2020-2023  润新知