聯賽膜你測試24 答題 題解
阿新 • • 發佈:2020-10-28
前言:
我嚴重懷疑這題是個卡常題。。。
最後把sort換成stable_sort才過去,人都傻了
解析:
首先要看對題啊,
上來整個雙重否定句,欺負我語文爛?那我也沒辦法嚶嚶嚶
大概意思就是,給你n個數,這些數顯然可以組成\(2^n\) 個數(每個數選或不選),要你選一個數,問至少要多大才能夠有不多於(1<<n)*(1-p) 個數比你的數大。
。。。。好像還是很繞
總之就是這樣啦
首先考慮爆搜,可以拿到30分的好成績,因為n>20以後,\(O(2^n)\)的複雜度就萎了。那這時怎麼辦呢?
可以考慮類似於折半搜尋的方法,先處理出前n/2個數能夠拼出的所有數,再處理出後n/2個數能夠拼出的所有數,最後再二分答案。
程式碼:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=1500000+10; const double eps=1e-9; int b[50]; ll a[maxn],c[maxn]; int n,tot,cnt; double p; ll ss; void dfs(int now,ll w){ if(now>n){ a[++tot]=w; return; } dfs(now+1,w); dfs(now+1,w+b[now]); } bool cmp(int x,int y){ return x<y; } void Solve1(){ dfs(1,0); sort(a+1,a+tot+1,cmp); double x=((double)tot*p); int y=(int)x; if(x-y>eps) y++; printf("%lld\n",a[y]); } void dfs2(int now,ll w){ if(now>(n/2)){ a[++tot]=w; return; } dfs2(now+1,w); dfs2(now+1,w+b[now]); } void dfs3(int now,ll w){ if(now>n){ c[++cnt]=w; return; } dfs3(now+1,w); dfs3(now+1,w+b[now]); } bool check(int x){ int head=1; ll res=0; for(register int i=cnt;i;--i){ while(c[i]+a[head]<=x){ if(head>tot) break; head++; } if(head>tot) break; res+=tot-head+1; } return res<ss ; } void Solve2(){ dfs2(1,0); dfs3(n/2+1,0); stable_sort(a+1,a+tot+1,cmp); stable_sort(c+1,c+cnt+1,cmp); double s=(double)(1ll<<n)*(1.0-p); ss=(ll)s; if(s-ss>eps) ss++; int l=1,r=a[tot]+c[cnt]; while(l<=r){ int mid=(l+r)>>1; if(check(mid)) r=mid-1; else l=mid+1; } printf("%d\n",l); } void Solve(){ scanf("%d%lf",&n,&p); for(register int i=1;i<=n;++i) scanf("%d",&b[i]); if(n<=20){ Solve1(); return; } Solve2(); } int main(){ freopen("answer.in","r",stdin); freopen("answer.out","w",stdout); Solve(); return 0; }