思考
首先产生的思路是,用小根堆的最小元素(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]); }
时间: 2024-12-29 01:58:32