1. 程式人生 > >2018.10.09 NOIP模擬 好數(雙向搜尋)

2018.10.09 NOIP模擬 好數(雙向搜尋)

傳送門 直接雙向搜尋出兩邊可行解,然後把兩邊的可行解合併起來得出答案就行了。 注意合併的時候可以利用排序和單調性優化時間複雜度。 直接列舉合併是O(sizasizb)O(siza*sizb)的。 但排序之後隨著aa集合中的乘積的增大,bb集合中的可行個數顯然是單調遞減的。 這樣就可以方便的統計答案了。 程式碼:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read(){
	ll ans=0;
	char ch=getchar();
	while(!isdigit
(ch))ch=getchar(); while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar(); return ans; } int k,tot=0,pos=0,mid; ll lim,pri[30],divv[30]; vector<ll>mul1,mul2; map<ll,int>S; inline void dfs1(int pos,ll mul){ mul1.push_back(mul); for(ll i=pos;i<=mid;++i){ ll b=mul; while
(lim/b>=divv[i])b*=divv[i],dfs1(i+1,b); } } inline void dfs2(int pos,ll mul){ mul2.push_back(mul); for(ll i=pos;i<=tot;++i){ ll b=mul; while(lim/b>=divv[i])b*=divv[i],dfs2(i+1,b); } } int main(){ k=read(),lim=read(); for(int i=1;i<=k;++i)pri[i]=read(); for(int i=1;i<=k;i+=2)divv[
++tot]=pri[i]; mid=tot; for(int i=2;i<=k;i+=2)divv[++tot]=pri[i]; dfs1(1,1),S.clear(),dfs2(mid+1,1),sort(mul1.begin(),mul1.end()),sort(mul2.begin(),mul2.end()); ll ans1=0,ans2=0,pos=mul2.size()-1; for(int i=0;i<mul1.size();++i){ while(lim/mul1[i]<mul2[pos])--pos,mul2.pop_back(); ans1+=pos+1,ans2=max(ans2,mul2[pos]*mul1[i]); } cout<<ans2<<'\n'<<ans1; return 0; }