挺好的一道题。
我只想到了用的丑数依次生成丑数,用优先队列来找最小的做法。
代码如下:
#include<iostream> #include<cstring> #include<cstdio> #include<queue> #include<set> #define mk(a) ((L){a}) #define inf 2147483647LL #define ll long long int #define rep(i,a,b) for(int i=(a);i<=(b);i++) using namespace std; const int maxn=111111; struct L{ ll x; bool operator < (const L &b)const{ return x>b.x; } }; priority_queue <L> qu; int k,n; ll p[maxn]; int main(){ cin>>k>>n; rep(i,1,k)cin>>p[i],qu.push(mk(p[i])); rep(i,1,n-1){ ll x=qu.top().x;//cout<<x<<endl; while(qu.top().x==x)qu.pop();//去重 rep(j,1,k)qu.push(mk(x*p[j])); } cout<<qu.top().x; return 0; }
然而这样生成的丑数太多了。实际上,光是就已经接近时限了。
实际上,我们只需要用到的丑数,后面过大的没有必要生成。
但每次暴力找到当前丑数所能生成的最小新丑数是的。
然后我们发现,找最小新丑数具有两个单调性。
对于每个丑数,其用到的质数是单调增的。
对于v每个质数,其用到的丑数也是单调增的。
使用第一个单调性的复杂度是,第二个是
。
显然我们只要使用第二个单调性就可以解决此题。
#include<iostream> #include<cstring> #include<cstdio> #define ll long long int #define rep(i,a,b) for(int i=(a);i<=(b);i++) using namespace std; const int maxn=111111; int k,n; ll p[maxn],f[maxn],cur[maxn];//cur记录当前p所用到的最大丑数 int main(){ scanf("%d%d",&k,&n); rep(i,1,k)scanf("%lld",&p[i]); memset(cur,0,sizeof(cur)); f[0]=1; rep(i,1,n){ ll mi=4000000000LL; rep(j,1,k){ while(p[j]*f[cur[j]]<=f[i-1])cur[j]++; if(p[j]*f[cur[j]]<mi)mi=p[j]*f[cur[j]]; } f[i]=mi; } cout<<f[n]; return 0; }