1. 程式人生 > >HDU 5878 -- 醜數打表(2016 ACM/ICPC Asia Regional Qingdao Online)

HDU 5878 -- 醜數打表(2016 ACM/ICPC Asia Regional Qingdao Online)

題目傳送門:http://acm.hdu.edu.cn/showproblem.php?pid=5878

題意:輸入一個n,要求找出比n大的,因子只有2,3,5,7的最小的數。

題解:首先說一下什麼是醜數,因子只有2,3,5,7的數就是醜數。。。。然後,該怎麼做呢?肯定不能從n開始,一個一個暴力找,從題目的樣例來看,當n是10的9次方時,要找兩萬多遍,會超時。如果做過醜數相關的題的話,就會知道其實10的9次方個數裡面,醜數其實不多,可以直接打表,然後通過二分法把離n最近的醜數找出來。怎麼打表就是關鍵了。

首先,第一個醜數為“1”,後面的每一個醜數都是有前一個醜數乘2、3、5或7而來,那麼後一個醜數就是前一個乘這四個數得到的最小值,for example:第一個:1,第二個:1*2、1*3、1*5或1*7,顯然為2,第三個:2*2,1*3,1*5或1*7,顯然是3,第四個:2*2,,2*3,1*5,1*7為4,第五個:3*2,2*3,1*5,1*7…… 

以下程式碼枚舉了5842個醜數,從小到大存在a數組裡面,輸出一下第5842個醜數,發現已經是2*10的9次方了

#include <iostream>  
#include <cstdio>  
#define min(a,b) ((a)<(b)?(a):(b))  
#define min4(a,b,c,d) min(min(a,b),min(c,d))  
using namespace std;  
int a[5850];  

int main()  
{  
    int n=1;
    int p2,p3,p5,p7;  
    p2=p3=p5=p7=1;  
    a[1]=1;  
    while(n<5843){  
        a[++n]=min4(2*a[p2],3*a[p3],5*a[p5],7*a[p7]);
        if(a[n]==2*a[p2])p2++;
        if(a[n]==3*a[p3])p3++;  
        if(a[n]==5*a[p5])p5++;  
        if(a[n]==7*a[p7])p7++; 
    }  
    return 0;  
}  
AC程式碼:
#include <iostream>  
#include <cstdio>  
#define min(a,b) ((a)<(b)?(a):(b))  
#define min4(a,b,c,d) min(min(a,b),min(c,d))  
using namespace std;  
int a[5850];  


int bSearch(int begin, int end, int e)
{
    int mid, left = begin, right = end;
    while(left <= right){
        mid = (left + right) >> 1;
        if(a[mid] >= e) right = mid - 1;
        else left = mid + 1;
    }
    return left;
}


int main()  
{  
    freopen("input.txt","r",stdin);  
    int n=1, T;
    int p2,p3,p5,p7;  
    p2=p3=p5=p7=1;  
    a[1]=1;  
    while(n<5843){  
        a[++n]=min4(2*a[p2],3*a[p3],5*a[p5],7*a[p7]);
        if(a[n]==2*a[p2])p2++;
        if(a[n]==3*a[p3])p3++;  
        if(a[n]==5*a[p5])p5++;  
        if(a[n]==7*a[p7])p7++; 
    }  
    cin>>T;
    while(T--){
          scanf("%d",&n);
          printf("%d\n",a[bSearch(1,5842,n)]);
    }
    return 0;  
}