POJ 1338 Ugly Numbers

[成绩]
Run IDUserProblemResultMemoryTimeLanguageCode LengthSubmit Time
6504064weweweer91338Accepted992K0MSG++2148B2010-03-02 19:40:21
6503693weweweer91338Accepted824K0MSG++1772B2010-03-02 18:36:01
6503581weweweer91338Wrong Answer

G++1427B2010-03-02 18:19:23
[报告]
    佳哥的课件里有这道题,看到了顺便就切掉了。
    首先,忽略6503581(那个和6503693一个算法,就是它没开LONG LONG,就WA了)。
    这里有两个算法:6503693是O(NlogN)的;6504064是O(N)的;还有个O(1)的,我没写。
    O(NlogN):就是佳哥课件里的那个算法。维护一个优先队列(二叉堆),每当从队首取出一个元素,都将它的2,3,5倍数加入队列。反复此过程,当取出N个数时,最后取出的数为最后的答案。
    O(N):这个是lordxfastx告诉我的一个算法。由于O(NlogN)中每取出的数*2,都必然比它前面取出的数*2小(3,5同理)。因此,可以维护3个单调队列,分别保存*2,*3,*5的值。每次取出的数为三个单调队列中队首的最小值。由于这个算法不需要多余的交换什么的,所以就是O(N)的。
    O(1):显然——打表……(不解释)
[程序]
6503693:


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#define func(x) inline static x
#define N 9973
using namespace std;
long long h[N+1];
long long a[N+1],n;
func(void) down(long x)
{
    long long i=x,j=x<<1,ax=a[x];
    while (j<=n)
    {
        if (j<n&&a[j]>a[j+1]) j++;
        if (ax>a[j])
        {
            a[i]=a[j];
            i=j;j=i<<1;
        }else break;
    }
    a[i]=ax;
}
func(void) up(long x)
{
    long long i=x,j=x>>1,ax=a[x];
    while (j>0&&ax<a[j])
    {
        a[i]=a[j];
        i=j;j=i>>1;
    }
//    if (a[j]!=ax)
        a[i]=ax;
//    else
//    {
    //    a[i]=a[n--];
    //    down(i);
    //}
}
long m=0;
func(bool) hash(long long x)
{
    long ax=x%N;
    while (h[ax]!=0&&h[ax]!=x) ax=(ax+1)%N;
    if (h[ax]==x) return true;
    else return !(h[ax]=x);
}
func(void) insert(long long x)
{
    if (hash(x)) return;
    m++;
    a[++n]=x;
    up(n);
}
func(void) erase()
{
    a[1]=a[n--];
    down(1);
}
func(void) print()
{
    printf("%d:",n);
    for (long i=1;i<=n;i++)
        printf("%d ",a[i]);
    printf("\n");
}
func(long long) solve(long k)
{
    memset(h,0,sizeof(h));
    memset(a,0,sizeof(a));
    m=0;
    n=1;
    a[1]=1;
    long long ax;
    while (k>1)
    {
        ax=a[1];
        k--;
        erase();
        insert(ax*2);
        insert(ax*3);
        insert(ax*5);
    //    print();
    }
    //cout << m << endl;
  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值