USACOTrainning.Section 3.1.Humble Numbers

上道Score Inflation已经是去年10月的事情了,之前卡在了Humble Numbers这道题了,其实这道在很早之前就做过了,在POJ上,不过给忘了,也不知道怎么做了。先说下题意,给定K个素数,求出第N个丑数,丑数的定义是,若干个数的乘积,而这些数都来自于之前给定的K个素数的集合。

想了个很暴力的方法,用一个最小堆来维护当前的最小的丑数,然后POP出去,用这个数和那K个素数相乘,判定是否唯一,然后放进最小堆,早就知道不行,还很弱的去写了一下,用STL实现,更加超时了,复杂度是O(K*N)。

参考了,官方的做法是用一个表,有序放丑数,假设有m个,第m+1个丑数,用素数集合中的数去和m个丑数相乘,第一个和某数相乘的丑数大于第m个丑数的话,它就有可能是第m+1个丑数,这些可能的值,取个最小的就是第m+1个丑数了,这样还不行,复杂度其实还是O(K*N),可以用二分的方法来加速,但也没把复杂度降下来。于是这个优化就很强大了,用一个数组记录乘积大于第m个丑数的位置,下次不从头开始枚举,而是从该位置开始枚举,就可以把复杂度降到O(K+N)了。

相比这些,我的那个暴力的方法每次不仅仅把第N个的算出来了,还把很多没用的数也算了出来,代码如下:

/*
ID: litstrong
PROG: humble
LANG: C++
*/
#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <math.h>
#include <queue>
#include <algorithm>
#include <string.h>
#include <stdio.h>
using namespace std;
 
const int MAX = 105;
const int MAXN = 100005;
 
int num[MAX], m_index[MAX];
int prime[MAXN];
 
int K, N;
 
class CNUM
{
public:
    int m_val;
    CNUM() {}
    CNUM(int m) : m_val(m) {}
    bool operator < (const CNUM &t) const
    {
        return m_val > t.m_val;
    }
};
 
int go()
{
    priority_queue<CNUM> Q;
    set<int> one;
    sort(num, num + K);
    Q.push(1);
    for(int i = 0; i <= N; i++)
    {
        int m_min = Q.top().m_val;
        //printf("%d %d\n", i, m_min);
        if(i == N)  return m_min;
        Q.pop();
        for(int j = 0; j < K; j++)
        {
            int m_num = m_min * num[j];
            if(one.find(m_num) == one.end())
            {
                one.insert(m_num);
                Q.push(CNUM(m_num));
            }
        }
    }
    return 0;
}
 
int go_ans()
{
    sort(num, num + K);
    memset(m_index, 0, sizeof(m_index));
    int top_num = 0;
    prime[top_num++] = 1;
    while(top_num <= N)
    {
        int m_min = -1;
        for(int i = 0; i < K; i++)
        {
            while(num[i] * prime[m_index[i]] <= prime[top_num - 1] && m_index[i] < top_num)
                m_index[i]++;
            if(m_index[i] < top_num)  
            {
                if(m_min == -1 || num[i] * prime[m_index[i]] < m_min)
                    m_min = num[i] * prime[m_index[i]];
            }
        }
        prime[top_num++] = m_min;
    }
    return prime[N];
}
 
int main()
{
    //freopen("humble.in", "r", stdin);
    //freopen("humble.out", "w", stdout);
 
    int k, n;
    scanf("%d%d", &K, &N);
    for(int i = 0; i < K; i++)
        scanf("%d", &num[i]);
    printf("%d\n", go_ans());
}
原文地址:https://www.cnblogs.com/litstrong/p/1970253.html