Humble Numbers
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 27221 Accepted Submission(s): 11982
Problem Description
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
Input
The input consists of one or more test cases. Each test case consists of one integer n with 1 <= n <= 5842. Input is terminated by a value of zero (0) for n.
Output
For each test case, print one line saying “The nth humble number is number.”. Depending on the value of n, the correct suffix “st”, “nd”, “rd”, or “th” for the ordinal number nth has to be used like it is shown in the sample output.
Sample Input
1
2
3
4
11
12
13
21
22
23
100
1000
5842
0
Sample Output
The 1st humble number is 1.
The 2nd humble number is 2.
The 3rd humble number is 3.
The 4th humble number is 4.
The 11th humble number is 12.
The 12th humble number is 14.
The 13th humble number is 15.
The 21st humble number is 28.
The 22nd humble number is 30.
The 23rd humble number is 32.
The 100th humble number is 450.
The 1000th humble number is 385875.
The 5842nd humble number is 2000000000.
Source
University of Ulm Local Contest 1996
思路
听说这是题dp,但是我死活不知道怎么dp。
根据题意,我认为 只要能由 2^a*3^b*5*c*7*d 这个构成就是丑数。
我的想法是遍历a,b,c,d将丑数放到数组里,再来个快排就ok了。
之前没注意数据的类型,不小心把一些数据定义为int导致,数据太大wa。
AC代码一
Accepted 1058 93MS 1724K 1426 B G++
#include<cstdio>
#include<cmath>
#include<iostream>
#include<string.h>
#include<algorithm>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
#define MAXN 5843
#define MAXM 1001
#define inf 0xffffffff
long long ans[MAXN];//dp[n][k]
int main() {
int k, n, num, flag = 1, flag1 = 1;
num = 0;
long long a, b, c, d, sum = 0;
a = b = d = c = 1;
for (int i = 0; i <= 32; i++, a = 2 * a)
{
if ((long long)a>2000000000)
{
break;
}
b = 1;
for (int j = 0; j <= 32; j++, b = 3 * b)
{
if ((long long)a*b>2000000000)
{
break;
}
c = 1;
for (int k = 0; k <= 32; k++, c = 5 * c)
{
if ((long long)a*b*c > 2000000000) {
break;
}
d = 1;
for (int p = 0; p <= 32; p++, d = 7 * d)
{
if ((long long)(a*b*c*d) <= 2000000000 && (long long)a*b*c*d>0)
{
ans[num] = (long long)(a*b*c*d);
if (num == 4526)
{
// printf("%lld %lld %lld %lld", a, b, c, d);
}
num++;
}
else {
break;
}
}
}
}
}
sort(ans, ans + num);
while (true)
{
char forma[4][3] = { "st","nd","rd","th" };
scanf("%d", &n);
if (n == 0) break;
printf("The %d%s humble number is %lu.\n", n, forma[n % 10 == 1 && n / 10 % 10 != 1 ? 0 : n % 10 == 2 && n / 10 % 10 != 1 ? 1 : n % 10 == 3 && n / 10 % 10 != 1 ? 2 : 3], ans[n - 1]);
}
}
后来我百度了下如何dp。
原来还可以通过最优队列,最优队列好像就是一个可以自动排序的数组。
每次将最小值取出分别乘以2 3 5 7 再放入队列。
AC代码二
Accepted 1058 109MS 1848K 930 B G++
# include<iostream>
# include<queue>
# define MAX 5842
long long ans[MAX + 1];
using namespace std;
struct cmp
{
bool operator()(long long &a, long long &b)
{
return a>b;//最小值优先
}
};
int main() {
priority_queue<long long, vector<long long>, cmp> q;
long num = 0, num1 = 0;
q.push(1);
while (!q.empty()) {
long long j;
while (true)
{
j = q.top();
q.pop();
if (j != ans[num - 1]) break;
}
ans[num++] = j;
q.push(2 * j);
q.push(j * 3);
q.push(5 * j);
q.push(7 * j);
if (num>MAX)
{
break;
}
}
while (true)
{
long long n;
char forma[4][3] = { "st","nd","rd","th" };
scanf("%lld", &n);
if (n == 0) break;
printf("The %lld%s humble number is %lld.\n", n, forma[n % 10 == 1 && n / 10 % 10 != 1 ? 0 : n % 10 == 2 && n / 10 % 10 != 1 ? 1 : n % 10 == 3 && n / 10 % 10 != 1 ? 2 : 3], ans[n - 1]);
}
return 0;
}
最后dp方法
根据官方题解
官方题解如下:
我们在数组hum中计算出前n个丑数。为了实现起来更简单,我们把1也作为一个丑数,算法也要因此略微调整一下。
当我们已知前k个丑数,想得到第k+1个,我们可以这样做:
对于每个质数p 寻找最小的丑数h 使得 h * p 比上一个丑数大 取我们找到的 h * p 中最小的一个:它就是下一个丑数
为了使搜索更快,我们可以为每个质数维护一个索引“pindex”表示每个质数已经乘到了哪个丑数,每次都从那里开始,而不是再从头再来。
状态转移方程:
ans[i] = min(ans[a]*2,ans[b]*3,ans[c]*5,ans[d]*7)
一开始 a b c d全指向第一个数 1。第一次取1*2,则把a++指向2。
ans[3]=min(2*2,1*3,1*5,1*7)这时取3,把b++指向2。ans[4] = min(2*2,2*3,1*5,1*7) 取4,把a++指向3。ans[5] = min(3*2,2*3,1*5,1*7)…..
AC代码三
Accepted 1058 109MS 1732K 1059 B G++
# include<iostream>
# include<queue>
# define MAX 5842
long long ans[MAX + 1];
using namespace std;
long long min(long a,long b,long c,long d) {
if (a <= b && a <= c &&a <= d) return a;
if (b <= a && b <= c &&b <= d) return b;
if (c <= a && c <= b &&c <= d) return c;
return d;
}
int main() {
long a, b, c, d, num = 2;
a = b = c = d = 1;
ans[1] = 1;
while (true) {
ans[num++] = min(ans[a] * 2, ans[b] * 3, ans[c] * 5, ans[d] * 7);
if (ans[num - 1] == ans[a]*2)
{
a++;
}
if (ans[num - 1] == ans[b] * 3)
{
b++;
}
if (ans[num - 1] == ans[c] * 5)
{
c++;
}
if (ans[num - 1] == ans[d] * 7)
{
d++;
}
if (num>MAX)
{
break;
}
}
while (true)
{
long long n;
char forma[4][3] = { "st","nd","rd","th" };
scanf("%lld", &n);
if (n == 0) break;
printf("The %lld%s humble number is %lld.\n", n, forma[n % 10 == 1 && n / 10 % 10 != 1 ? 0 : n % 10 == 2 && n / 10 % 10 != 1 ? 1 : n % 10 == 3 && n / 10 % 10 != 1 ? 2 : 3], ans[n]);
}
return 0;
}
最后就这题而言,好像是我的数组加快排的效率高点。。。