Usaco Training Section 3.1 Humble Numbers
阿新 • • 發佈:2018-11-12
給你一個素數集合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]}
這樣複雜度就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]); }