[usaco3.1.3]humble

 这道题想了很久想不到,只好看题解(在下服气),题解是666的,不用多说上代码。

  第一个是官方题解:记录下到第i-1个丑数时,每一个素数枚举到哪一个丑数,然后直接从那个丑数继续开始枚举。

  第二个是手写堆+set判重,每一次取出最小的数作为第i个丑数,然后枚举每一个素数扩展新元素加入堆,再用set判重。

/*
ID:abc31261
LANG:C++
TASK:humble
*/
#include<cstdio>
#include<cstring>
#include<map>
#include<iostream>
using namespace std;
const int maxn=200,maxm=700000;
long long num[maxn],hash[maxm+1],f[maxn],len,hum[maxm];//f数组就是记录枚举到哪一个。

void add(int x)
{
     int i=x%maxm,j=i+1;
     if (hash[i]==0)hash[i]=x;
        else
        {
             while (j!=i && hash[j]!=0)j=(j+1)%maxm;
             hash[j]=x;
        }
}

int check(int x)
{
    int i=x%maxm,j=i+1;
    if (hash[i]==x)return 1;
       else
       {
            while (j!=i && hash[j]!=x && hash[j]!=0)j=(j+1)%maxm;
            if (hash[j]==x)return 1;
       }
    return 0;
}
int main()
{
    int i,j,k,n,l,p,q;
    freopen("humble.in","r",stdin);
    freopen("humble.out","w",stdout);
    scanf("%d%d",&k,&n);
    memset(hash,0,sizeof(hash));
    memset(f,0,sizeof(f));
    for (i=1;i<=k;i++)scanf("%d",&num[i]);
    hum[1]=len=1;                                //为了方便,把1也看作一个丑数。
    for (i=1;i<=n;i++)
    {
        int l=0;
        for (j=1;j<=k;j++)
        {
            while (check(num[j]*hum[f[j]+1])==1)f[j]++;
            if ((num[j]*hum[f[j]+1]<num[l]*hum[f[l]+1])|| l==0)l=j;  //枚举
        }
        hum[++len]=num[l]*hum[++f[l]];
        add(hum[len]);
    }
    cout<<hum[len]<<endl;
    return 0;
}
/*
ID:abc31261
LANG:C++
TASK:humble
*/
#include<cstdio>
#include<cstring>
#include<set>
#include<iostream>
using namespace std;
const int maxn=200,maxm=100000;
set<long long> s;
long long heap[maxm*4],len=0;
int k,n,num[maxn];

long long get()
{
    long long i=1,x=heap[1];
    swap(heap[1],heap[len--]);
    while (i*2<=len)
    {
          int j=i*2;
          if (i*2+1<=len && heap[i*2+1]<heap[i*2])j=i*2+1;
          if (heap[i]>heap[j])
          {
             swap(heap[i],heap[j]);
             i=j;
          }
          else break;
    }
    return x;
}

void put(long long x)
{
     long long i=++len,j;
     heap[len]=x;
     while (i>1)
     {
           if (heap[i/2]>heap[i])
           {
              swap(heap[i/2],heap[i]);
              i=i/2;
           }
           else break;
     }
     if (len>n)len=n;
}
int main()
{
    int i,j;
    long long x;
    freopen("humble.in","r",stdin);
    freopen("humble.out","w",stdout);
    memset(heap,0,sizeof(heap));
    cin>>k>>n;
    for (i=1;i<=k;i++)scanf("%d",&num[i]);
    put(1);                  //把1看作一个丑数
    for (i=1;i<=n;i++)
    {
        x=get();
        for (j=1;j<=k;j++)
            if (s.count(num[j]*x)==0)
            {
               put(num[j]*x);
               s.insert(num[j]*x);
            }
    }
    cout<<get()<<endl;
    return 0;
}
时间: 2024-10-27 06:35:20

[usaco3.1.3]humble的相关文章

Humble Numbers(丑数) 超详解!

给定一个素数集合 S = { p[1],p[2],...,p[k] },大于 1 且素因子都属于 S 的数我们成为丑数(Humble Numbers or Ugly Numbers),记第 n 大的丑数为 h[n]. 算法 1: 一种最容易想到的方法当然就是从 2 开始一个一个的判断一个数是否为丑数.这种方法的复杂度约为 O( k * h[n]),铁定超时(如果你这样做而没有超时,请跟 tenshi 联系) 算法 2: 看来只有一个一个地主动生成丑数了 : 我最早做这题的时候,用的是一种比较烂的

zoj 1095 - Humble Numbers

题目:找到用2,3,5,7为数的因第n个数字. 分析:dp,数据结构.类似于合并果子的队列维护,用4根指针分别指向队列,用当前的数乘以对应数字即可. 说明:(2011-09-19 01:42) #include <iostream> using namespace std; int F[ 5845 ]; int n[ 4 ] = {2,3,5,7}; int p[ 4 ]; int main() { F[ 1 ] = 1; for ( int i = 0 ; i < 4 ; ++ i )

poj 2247 Humble Numbers

Humble Numbers Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9453   Accepted: 4440 题目大意:找出所有因子中只有2,3,5,7的数,给出n,求出第n个这样   只有6000不到打表 注意第11  12  13 的输出与 1   2   3    几十一   几十二   几十三 的输出不同 #include <iostream> #include <algorithm> u

洛谷P2723 丑数 Humble Numbers [2017年 6月计划 数论07]

P2723 丑数 Humble Numbers 题目背景 对于一给定的素数集合 S = {p1, p2, ..., pK},考虑一个正整数集合,该集合中任一元素的质因数全部属于S.这个正整数集合包括,p1.p1*p2.p1*p1.p1*p2*p3...(还有其 它).该集合被称为S集合的“丑数集合”.注意:我们认为1不是一个丑数. 题目描述 你的工作是对于输入的集合S去寻找“丑数集合”中的第N个“丑数”.所有答案可以用longint(32位整数)存储. 补充:丑数集合中每个数从小到大排列,每个丑

usaco 3.1 Humble Numbers

给出K个素数,从这些数中取出任意个,每个数乘上任意遍,得到的这些数的集合叫做丑数,求集合中第N小的数. 一般的做法是,将这些素数放入优先队列,将队首元素弹出,将这个队首元素乘上每个素数的结果存入队列,从队列中pop出的第N个数就是第N小. 但这种做法在一些特殊输入下会导致队列内存爆掉. 另一种效率更高的的做法是:给每个素数设置一个计数器,计数器中的值表示它和已知的前i小个丑数已经乘 /* ID: modengd1 PROG: humble LANG: C++ */ #include <iostr

HDU 丑数 - 1058 Humble Numbers

这一题是讲了一个名叫丑数的概念(为啥叫丑数,,). 概念:因子中仅仅包含2.3.5,7的数,称为丑数.但其实我百度网上时,发现正常的丑数应该是因子中仅仅包含2.3.5,不过基本都一样. 我们可以通过不断mod2,3,5,7,直到无法在摸,验证此时是否为1来判断该数是否为丑数,但是这样的方法太过浪费时间,所以介绍一种新的方法,下面方法摘自这里点击打开链接. 根据丑数的定义,丑数应该是另一个丑数乘以2.3,5或者7的结果(1除外).因此我们可以创建一个数组,里面的数字是排好序的丑数.里面的每一个丑数

HDU 1058 Humble Numbers--DP--(计数器技巧)

题意:输出第n大的质因数只有2,3,5,7的数 分析:预处理满足这些条件的数,然后输出dp[n]就行,满足条件的数无非就是2,3,5,7不断的做乘积 这题的关键就是如何把这些乘积从小到大存入数组:设置四个计数器p2,p3,p5,p7完成这个任务 代码: #include<iostream> #include<cstdio> #define min(a,b) (a<b?a:b) using namespace std; int n,dp[6000]; void check()

hdu 1058 Humble Numbers(构造?枚举?)

题意: 一个数的质因子如果只是2,3,5,7中的若干个.则这个数叫做humble number. 例如:1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 24, 25, 27, ... 给n,问第n个humble number是多少. 思路: 所有的humble数的构造都是:(2^a)*(3^b)*(5^c)*(7^d).a,b,c,d大于等于0. X=a+b+c+d代表这个数是第X个humble数. 假设前i-1个humble

usaco-3.1-PROB Shaping Regions-漂浮法

漂浮法,顾名思义,就是一块块的往上飘. 以逆序来进行放置,即n to 1.逆序的好处在于放置一个矩形后,俯视看到的就是最终俯视该矩形应该看到的.因为挡着它的矩形在之前已经放置好了,所以可直接统计,为递归创造了条件.每放一个矩形,可以想象成将其扔入一密度很大的海水底部,海分成了n层,然后矩形开始向上浮.在上浮过程中若碰撞到其他的矩形则断裂成几个小矩形,继续上浮,直到浮出水面.于是想到用个递归来模拟上浮过程. /* ID: rowanha3 LANG: C++ TASK: rect1 */ #inc