【BZOJ】4800 [Ceoi2015]Ice Hockey World Championship 折半查找

题目传送门

上次省选就有大佬提过折半查找,但是因为我过于蒟蒻,所以一直都没有去学习这种算法。

今天突发奇想,开了一发脑洞,学习一下这种算法。

这题的折半查找思想是非常好的,可以优化许多题目,可以把时间复杂度硬生生降一半。(好强的算法。)

折半查找,就是把数据分成两半,分别对它们进行操作,然后考虑这两半数据间的联系。(这TMD不是分治吗?)

对于这题来说,就是把物品分成两半,然后分别求可行的物品选取方案,然后考虑两组数据组合后的选择方案,两者相加就是答案。

附上AC代码:

#include <cstdio>
#include <cctype>
#include <algorithm>
#define N 41
#define M (1<<20)+10
using namespace std;

long long n,m,a[N],f[2][M],l,r,mid,ret,ans;

inline char nc(){
	static char ch[100010],*p1=ch,*p2=ch;
	return p1==p2&&(p2=(p1=ch)+fread(ch,1,100010,stdin),p1==p2)?EOF:*p1++;
}

inline void read(long long &a){
	static char c=nc();int f=1;
	for (;!isdigit(c);c=nc()) if (c=='-') f=-1;
	for (a=0;isdigit(c);a=a*10+c-'0',c=nc());
	a*=f;return;
}

inline void so(int x,int y,long long sum,int c){
	if (sum>m) return;
	if (x==y){
		f[c][++f[c][0]]=sum;
		return;
	}
	so(x+1,y,sum+a[x],c),so(x+1,y,sum,c);
	return;
}

int main(void){
	read(n),read(m);
	for (int i=1; i<=n; ++i) read(a[i]);
	so(1,(n>>1)+1,0,0),so((n>>1)+1,n+1,0,1);
	sort(f[0]+1,f[0]+f[0][0]+1),sort(f[1]+1,f[1]+f[1][0]+1);
	for (int i=1; i<=f[0][0]; ++i){
		l=1,r=f[1][0],ret=0;
		while (l<=r)
			if (f[1][mid=(l+r)>>1]<=m-f[0][i]) ret=mid,l=mid+1;
				else r=mid-1;
		ans+=ret;
	}
	printf("%lld",ans);
	return 0;
}

10.21

话说这题怎么变成权限题了?搞得我又要用YF大佬的号进去看题了……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值