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