USACO humble,动态规划简直快得吐血(对比类似treap思路)

第一感觉是用类似于treap的方法,不过treap我没有独立实现过,怕细节上出错,但是思想还是可以借鉴的,于是就想到用STL的set来帮忙。看下面的图就知道了。只要在树中的节点就是可以扩展的节点,所以绿色嘛,黑色表示正在扩展的节点,蓝色就是扩展出来的数字。节点中的两笔数据 value 和 next,value就是当前节点已经扩展到了哪个humble数字,next就是接下来要扩展时,value需要乘以第几个输入的质数。

不过,有点慢,虽然也不是很慢。复杂度的话,最坏时树中节点数kn,所以应该就是O(nlogkn)。确实不算很快,所以我又写了后来的动态规划的版本,飞起来了。不过写贴上这个版本的代码吧。

/*
ID:fairyroad
LANG:C++
TASK:humble
*/
#include<fstream>
#include<set>
using namespace std;
ifstream fin("humble.in");
ofstream fout("humble.out");
size_t k, n;
long long  p[100];
struct node
{
    long long value;
    size_t next;
    node() : value(0), next(0) {}
    node(long long v, size_t n) : value(v), next(n) {}
};

struct comp
{
    bool operator()(const node& p1, const node& p2)
    {
        return p1.value*p[p1.next] < p2.value*p[p2.next];
    }
};

int main()
{
    fin>>k>>n;
    for(size_t i = 0; i < k; ++i)
        fin>>p[i];

    set<node, comp> coll;
    set<node, comp>::iterator pos;
    coll.insert(node(1, 0));
    size_t num = 0, idx;
    long long min, v;
    while(num < n)
    {
        ++num;
        pos = coll.begin();
        v = pos->value, idx = pos->next;
        min = v*p[idx];
        if(idx+1 < k)
            coll.insert(node(v, idx+1));
        coll.erase(pos);
        coll.insert(node(min, idx));
    }
    fout<<min<<endl;
    return 0;
}

值得一提的是,空间复杂度也是很高的。看测试结果就知道了,算是不优雅的通过了。



动态规划的基本思路是,我们在数组hum中计算出前n个丑数。当我们已知前k个丑数,想得到第k+1个时,就去寻找对于每个质数p的寻找最小的丑数h,使得h*p比第k个丑数大。复杂度是O(KN),空间复杂度更是稳定的O(N),实在是精彩啊!

好像也不是多么严格的动态规划,但是符合记忆化搜索的思维。思维最重要,具体是不是倒是其次了。



/*
ID:fairyroad
LANG:C++
TASK:humble
*/
#include <fstream>
#include<climits>
using namespace std;
ifstream fin("humble.in");
ofstream fout("humble.out");
int k, n;
int p[100], start[100];
long long res[100001];

int main()
{
    fin>>k>>n;
    for(int i = 0; i < k; ++i)
        fin>>p[i], start[i] = 0;
    int num = 0;
    res[num++] = 1;
    while(num <= n)
    {
        int index = 0;
        long long min = LONG_LONG_MAX;
        for(int i = 0; i < k; ++i)
        {
            while(p[i] * res[start[i]] <= res[num-1])
                ++start[i];
            if(p[i] * res[start[i]] < min) {
                min = p[i] * res[start[i]];
                index = i;
            }
        }
        res[num++] = min;
        ++start[index];
    }

    fout<<res[n]<<endl;
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值