1. 程式人生 > >[usaco]醜數

[usaco]醜數

truct open 如果 ++ i+1 hid pri names close

思考

首先產生的思路是,用小根堆的最小元素(top)來與 k個數 相乘,之後把結果再扔進小根堆,每次操作得到的即是第k小。 不過要註意一下判重。但是非常悲劇的是 在遇到極限數據的時候TLE了。在思索無果的情況下,偷偷去看了發題解。發現題目的解法還是比較巧妙的。

技術分享
#include <queue>
#include <cstdio>
#include <iostream>
#define LL long long
using namespace std;
LL num[105],ans[100005],cnt;
struct node{
    LL x;
    
bool operator < (const node A)const{ return x>A.x; } node(LL x){ this->x=x; } }; priority_queue<node>s; int main(){ LL k,n,i; scanf("%lld%lld",&k,&n); for(register int i=1;i<=k;i++){ scanf("%lld",&num[i]); } s.push(node(
1)); while(cnt<=n){ LL x = s.top().x; s.pop(); if(ans[cnt]<x){ ans[++cnt]=x; for(register int i=1;i<=k;i++) s.push(node(num[i]*x)); } } printf("%lld",ans[n+1]); }
這裏附上82分的TLE代碼

題解的思路是什麽呢? f[i]表示第i小 那麽f[i]一定大於f[i-1] 我們要做的是 f[i]大於f[i-1] 並盡量的小(讀者:這不是廢話嗎?)

其次 f[i]一定是這k個數中的某個數 乘 f[i-1]或者f[i-2]或者f[i-3]....得來的,那麽思路就出來了。 但是這三層循環還是有可能TLE。所以要進一步優化.

很容易發現滿足條件的醜數x*a[j]>f[i-1],一定滿足條件,x*a[j]>f[i-2];於是我們就可以從滿足x*a[j]>f[i-2]的醜數x的位置往後枚舉,找到滿足條件x*a[j]>f[i-1]的醜數。

然後和min比較。

#include <cstdio>
#include <iostream>
typedef unsigned long long ll;
using namespace std;
const int maxn=100011;
ll Num[123],f[maxn],jl[maxn];
ll n,MIN,k;
int main(){
    scanf("%lld%lld",&k,&n);
    for(int i=1;i<=k;i++) scanf("%lld",&Num[i]);
    f[0]=1;
    for(int i=1;i<=n;i++){
        MIN=3e9;
        for(int j=1;j<=k;j++){
            //為什麽要jl[j]++ 因為如果不加的話 到f[i+1] f[jk[j]]*Num[j] 一定也是<=f[i] 
            //其次 s[j]存的是a[j]至少與第幾小醜數相乘才能得到一個比f[i-1]大的醜數 
            while(Num[j]*f[jl[j]]<=f[i-1]) jl[j]++; 
            MIN = min(MIN,Num[j]*f[jl[j]]);
        }
        f[i] = MIN;
    }
    printf("%lld",f[n]);
}

[usaco]醜數