A number whose only prime factors are 2,3,5 or 7 is called a humble number. The sequence 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 24, 25, 27, ... shows the first 20 humble numbers.
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 );
}
}