Write a program to find and print the nth element in this sequence. (1 <= n <= 5842)
容易想到用一个按照自然顺序递增的循环一个一个去判断是否满足2a1 * 3a2 * 5a3 * 7a4,并且将满足的数依次放入数组中直至第n个时结束输出。但是由于当n = 5842时结果为20亿(也就是说要循环20亿次!),time limited Exceeded!不可行。
重新考虑后给出如下解答:
将结果放入数组r中,在假设已求得前n-1个f的情况下第n个应该有这样的形式:
r[n] = min{2 * r[i1],3 * r[i2],5 * r[i3],7 * r[i4]},其中i1,i2,i3,i4待定且均小于等于n-1。
接下来需要确定i1,i2,i3,i4,容易得出唯一确定的条件:
r[i-1] <= r[n-1]/b < r[i], (b,i) = { (2.0,i1), (3.0,i2), (5.0,i3), (7.0,i4) }, (这里要注意了,不是b*r[i-1] <= r[n-1] < b*r[i] 因为b*r[i]会超过43亿溢出)
再由r中的结果是按升序排列的,即可以用二分法查找出满足的i1,i2,i3,i4。
还可以做一个小小的改进,当求出r[n]后保留此时的i1,i2,i3,i4,因为决定r[n+1]的i1,i2,i3,i4一定比决定r[n]的要大,这样可以减少查找的次数。
Accepted | 1095 | c | 00:00.02 | 420K |
int n,t=20;
int i1,i2,i3,i4;
long r[5843] = {0,1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 24, 25, 27};
void output(int k)
{
if(n%100>=10 && n%100<=20)
{
printf("The %dth humble number is %ld.",n,r[n]);
return;
}
switch( k )
{
case 1:
printf("The %dst humble number is %ld.",n,r[n]);
break;
case 2:
printf("The %dnd humble number is %ld.",n,r[n]);
break;
case 3:
printf("The %drd humble number is %ld.",n,r[n]);
break;
default:
printf("The %dth humble number is %ld.",n,r[n]);
break;
}
}
int search(int s,int e,int n,double b)
{
int i=e;
double temp = r[n]/b;
while(!(((double)r[i-1] <= temp) && (temp < (double)r[i])))
{
i = (e+s)/2;
if((double)r[i] <= temp)
s = i;
else
e = i;
}
return i;
}
void solve()
{
if(n>t)
{
int m = t+1;
while(m <= n)
{
i1 = search(i1,m-1,m-1,2);
i2 = search(i2,m-1,m-1,3);
i3 = search(i3,m-1,m-1,5);
i4 = search(i4,m-1,m-1,7);
r[m++] = min4(2*r[i1],3*r[i2],5*r[i3],7*r[i4]);
t++;
}
}
output(n%10);
}
void main()
{
i1 = i2 = i3 = i4 = 1;
while((scanf("%d",&n)!=EOF) && (n!=0))
{
solve();
putchar(10);
}
}