首页 > 代码库 > [usaco]丑数

[usaco]丑数

思考

首先产生的思路是,用小根堆的最小元素(top)来与 k个数 相乘,之后把结果再扔进小根堆,每次操作得到的即是第k小。 不过要注意一下判重。但是非常悲剧的是 在遇到极限数据的时候TLE了。在思索无果的情况下,偷偷去看了发题解。发现题目的解法还是比较巧妙的。

技术分享
#include <queue>#include <cstdio>#include <iostream>#define LL long longusing 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]丑数