Usaco Training Section 3.1 Humble Numbers

给你一个素数集合S。若一个数的素因子均属于S,则该数为丑数。求第n个丑数。

这题出得很妙,正解不好想。

法一:set

先把S中每个数放入set。每次取出set中的最小数,即为第i个丑数,并从s中删除。再将它乘S中的所有数,放入set。

这个复杂度还行,O(nklog(n)),会t一个点。

#include<bits/stdc++.h>
#define ll long long
using namespace std;

inline int read(){
    int x=0;char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x;
}

set<ll> s;
int a[101];
int main()
{
    freopen("humble.in","r",stdin);
    freopen("humble.out","w",stdout);
    int k=read(),n=read();
    for(int i=1;i<=k;++i) a[i]=read(),s.insert(a[i]);
    for(int i=1;i<n;++i){
        int x=*s.begin();s.erase(s.begin());
        for(int j=1;j<=k;++j) s.insert((ll)x*a[j]);
    }
    printf("%d\n",*s.begin());
}

这个方法其实还比较好想(反正我是自己想出来的),后一个方法就是神犇才能想出来的看题解的。

法二(正解)

有了第一个tle的方法,我们可以尝试优化。首先外循环O(n)少不了。我们就只能优化中间的构造丑数的部分。

考虑到丑数的一种单调性,即对于任意a[j](S中的第j个数),若a[j]*ans[x]<=ans[i],则a[j]*ans[x]<=ans[m](m>i)。

即若a[j]*ans[x]<=ans[i],则用a[j]更新时,ans[1]~ans[x]就再也不会有用了。

于是,求ans[i]时,对于a[j],我们每次只需找最小的x,使得a[j]*ans[x]>ans[i-1]。a[i]=min{a[j]*ans[x]}

扫描二维码关注公众号,回复: 3594364 查看本文章

这样复杂度就OK了,O(nk)。(维护每个x的总次数为n,所以2个嵌套for循环次数为nk+n,维护总次数为nk,程序循环次数为2nk+n)

#include<bits/stdc++.h>
#define ll long long
using namespace std;

inline ll read(){
    int x=0;char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x;
}

ll a[101],ans[100001],s[100001];
int main()
{
    freopen("humble.in","r",stdin);
    freopen("humble.out","w",stdout);
    ll k=read(),n=read();
    for(ll i=1;i<=k;++i) a[i]=read();
    ans[0]=1;
    for(ll i=1;i<=n;i++){
        ll x=2147483647;
        for(ll j=1;j<=k;j++){
            while(a[j]*ans[s[j]]<=ans[i-1]) s[j]++;
            x=min(x,a[j]*ans[s[j]]);
        }
        ans[i]=x;
    }
    printf("%d\n",ans[n]);
}

猜你喜欢

转载自blog.csdn.net/qq_36911709/article/details/81210267