课程29_24 1426 分数数列2
题目:
题目描述:
已知一个分数数列的如下:1/2,3/5,4/7,6/10,8/13,9/15,…。输入该数列的第n项,输出对应项的值(用分数表示)
其中0<n<=3000
输入描述:
多组输入,每组输入一个正整数n,表示该数列的第n项
输出描述:
对应于每组输入,输出该项对应的分数表示的值。
样例输入:
2011
样例输出:
3253/5264
解析:
这道题代码倒是不难,主要是研究这个数列究竟是什么规律。那么这道题就变成了一道小学找规律题。
那么,如何快速的发现这道题的数列规律呢?这里教大家一个野路子,如果感兴趣的可以看一看,不感兴趣的略过即可。
大部分的OJ系统都是可以查看其他人做这道题的结果的,我们查询一下这道题的AC(就是通过的)数据,发现绝大部分的人通过的耗时都是20ms~40ms。
在OJ里,这个耗时可以反映出你的算法的时间复杂度,如果说这道题的数列是有通项公式的,那么一般耗时都是O(1)或者O(n),也就是0ms,但是通过的代码都有耗时,说明要么通项公式里混有高时间复杂度(至少为O(n))的项(比如组合数、阶乘),要么就说明式子根本没有通项公式。顺着这两个思路去思考,式子很快就出来了。
那么如果查询的结果发现基本上都是0ms,那么就从通项公式的角度去思考,也能很快的得到答案。
下面正式讲解规律的寻找:
首先,一个数列可能存在不止一个规律,我们的目标就是能找一个是一个,然后再根据已经找到的规律继续找。首先这个数列最显眼最一眼能看出来的,就是分子和分母的差。很明显:第一个数字的分子减分母是1,第二个为2,第三个为3……然后再根据题目给出的第2011项确认一下,第2011项差2011,说明这个规律是正确的。
接下来我们顺着这个思路去找,既然分子和分母的值是相对确定的(即确定了其中一个就能确定另外一个),那么我们就想办法确定其中一个。我们敏锐的发现,分子似乎从来都不重复,分母也是,所以我们猜测:分子可能是从来没有使用过的数字之中最小的那个。比如说第二项的分子3,就是因为1和2都被用过了,所以用了3,而第三项的分子4,是因为1、2、3、5都被用过了,所以选择了4。我们在不考虑运行速度的情况下写一个代码跑一下,发现2011项真的是3253/5264,那么这道题的规律就被我们找到了。
解题:
在代码部分,我用了预处理的方法。预处理主要是用来针对多组输入的。如果题目给出的数据是多组输入,那么传统的做法是每给一个数据就算一次,这样会出现很多重复计算。而预处理是在输入之前就把所有的数据全部算出来,然后给什么数据就输出什么数据,无论输入的数据量有多少,运行时间都不会有太大的变化。
在接下来的题目中,我还会讲到一种预处理的变体,思路是“算到哪存到哪”,从平均耗时上比预处理更优秀。
参考代码:
// TSOJ-1426 分数数列2
#include <iostream>
using namespace std;
bool use[10000]={0};
int son[3001]={0}, father[3001]={0};
int now=0;
void _init(void)
{
for(int i=1;i<3000;i++)
{
for(int s=i*1.6;s<=i*3;s++)
{
if(!use[s])
{
use[s] = true;
use[s+i+1] = true;
son[i+1] = s;
father[i+1] = s+i+1;
break;
}
}
}
}
int main()
{
son[1] = 1;
father[1] = 2;
use[0] = use[1] = use[2] = true;
_init();
int n;
while(cin>>n)
{
cout<<son[n]<<'/'<<father[n]<<endl;
}
return 0;
}
本文详细解析了1426题分数数列的规律,通过观察分子与分母的差来找到规律,并提供了解题思路,强调了预处理在解决多组输入问题中的应用。

被折叠的 条评论
为什么被折叠?



