ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

折半搜索——另类的二分法

2021-12-03 12:04:33  阅读:164  来源: 互联网

标签:折半 dep sum 另类 long 二分法 int read void


折半搜索

前置知识

笼统的二分
\(dfs\)
清醒的头脑

思路

对于一些很暴力的爆搜,我们发现如果使用通常的搜索会炸。会发现,我们通常的搜索有很多状态是冗余的根本不可能实现的,但是又不得不去搜索,所以说,整体二分可以使这些无法实现的冗余状态少搜一点。

网上找到一个好图

典型例题

传送门

洛谷 P4799 [CEOI2015 Day2]世界冰球锦标赛

作为一道普及组入门题,我也觉得不过分,但是再看一眼数据 \(N \leq 40\) ,众所周知,这题普通的爆搜时间复杂度是 \(\mathbf{O}(2^N)\) ,明显是不行的,那么应该怎么做呢?

他这个题是要求,选出一些数,然后他们的总和不可以超过 \(M\) ,挺套路的二分。

我现在把他分成两堆数,比如说样例的 \(100\quad1500\quad500\quad500\quad1000\)

现在就变成了

\(100\quad1500\)
\(500\quad500\quad1000\)

那分成这样有什么用呢?
我现在对每一堆数据分别做 \(\mathbf{O}(2^N)\) 的爆搜,然后找出他们可以组成多少钱的门票。
对于第二堆数排序。
然后对第一堆数一个一个的分析,二分在第二堆数中找到恰好合法的那个地方,前面的必定全部合法,那么这题就挺简单了啦。

#include <bits/stdc++.h>
#define debug puts("I ak IOI several times");
#define pb push_back
#define int long long
using namespace std;
template <typename T>inline void read(T& t){
    t=0; register char ch=getchar(); register int fflag=1;
    while(!('0'<=ch&&ch<='9')){if(ch=='-') fflag=-1;ch=getchar();}
    while(('0'<=ch&&ch<='9')){t=((t<<1)+(t<<3))+ch-'0'; ch=getchar();} t*=fflag;
}
template <typename T,typename... Args> inline void read(T& t, Args&... args){
    read(t);read(args...);
}
template <typename T>inline void write(T x){
    if(x<0) putchar('-'),x=~(x-1); int s[40],top=0;
    while(x) s[++top]=x%10,x/=10; if(!top) s[++top]=0;
    while(top) putchar(s[top--]+'0');
}
long long n,a[50],b[50],na,nb;
long long posa[1<<21],posb[1<<21],m;
long long cnta,cntb;
void dfs1(long long dep,long long sum){
	if(dep>na){
		posa[++cnta]=sum;
		return;
	}
	dfs1(dep+1,sum+a[dep]);
	dfs1(dep+1,sum);
}
void dfs2(long long dep,long long sum){
	if(dep>nb){
		posb[++cntb]=sum;
		return;
	}
	dfs2(dep+1,sum+b[dep]);
	dfs2(dep+1,sum);
}
#undef int
int main(){
	
#define int long long
	read(n,m);
	na=(n+1)/2;nb=n/2;
	for(int i=1;i<=na;++i) read(a[i]);
	for(int i=1;i<=nb;++i) read(b[i]);
	dfs1(1,0);
	dfs2(1,0);
	//sort(posa+1,posa+cnta+1);
	sort(posb+1,posb+cntb+1);
	int ans=0;
	for(int i=1;i<=cnta;++i)
		ans+=(upper_bound(posb+1,posb+cntb+1,m-posa[i])-posb-1);
	cout<<ans<<endl;
    return 0;
}
//Welcome back,Chtholly.

标签:折半,dep,sum,另类,long,二分法,int,read,void
来源: https://www.cnblogs.com/Mercury-City/p/15637240.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有