有道难题练习赛 - 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种情况,全部枚举出来。

posted @ 2010-05-25 10:58  InfantSorrow  阅读(614)  评论(0编辑  收藏  举报