联赛膜你测试24 答题 题解

前言:

我严重怀疑这题是个卡常题。。。

最后把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
",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
",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;
}

原文地址:https://www.cnblogs.com/wwcdcpyscc/p/13887756.html