• 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());
    }
  • 相关阅读:
    css3 可穿透的盒子标签属性 pointer-events
    Visual Basic 6.0精简版下载地址
    VB实现七彩过渡渐变色效果
    ExcelVBA联考中学校自动分配
    VB经典的推箱子小游戏源程序
    坦克大战小游戏源程序
    扫雷初级版V1.0源程序
    班级随机点名程序
    VB弹力球源程序
    老师如何听课和评课?4个维度、20个观察视角、68个观察点!
  • 原文地址:https://www.cnblogs.com/litstrong/p/1970253.html
Copyright © 2020-2023  润新知