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

转载于:https://www.cnblogs.com/CCBB/archive/2010/05/25/1743414.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值