算法介绍:
折半搜索常用于复杂度O(n!)级的搜索问题,当我们发现很显然可以将问题划分为两部分分别搜索枚举,再合二为一求出最终答案时,我们可以选择使用折半搜索。
常见数据规模:
对于答案的值域往往没有要求,只对给出元素个数 n n n 有一定要求:
例题:

解题思路:
设目标值x为 g o a l goal goal,最终种类数为 a n s ans ans。
如果纯暴力解决,算法复杂度为 O ( 2 n ) O(2^n) O(2n),而 n n n最大可达到 40 40 40,显然是会超时的
所以我选择先枚举出前半部分元素,即 t 1 ∼ t n / 2 {t_1} \sim {t_{n/2}} t1∼tn/2所能生成的所有值 t o t 1 tot_1 tot1所组成的集合 s s s。
再去搜索 
     
      
       
        
        
          t 
         
         
         
           n 
          
         
           / 
          
         
           2 
          
         
           + 
          
         
           1 
          
         
        
       
         ∼ 
        
        
        
          t 
         
        
          n 
         
        
       
      
        {t_{n/2+1}} \sim {t_{n}} 
       
      
    tn/2+1∼tn能组合产生的所有的值 
     
      
       
       
         t 
        
       
         o 
        
        
        
          t 
         
        
          2 
         
        
       
      
        tot_2 
       
      
    tot2,对于每次搜索产生的 
     
      
       
       
         t 
        
       
         o 
        
        
        
          t 
         
        
          2 
         
        
       
      
        tot_2 
       
      
    tot2,都去 
     
      
       
       
         s 
        
       
      
        s 
       
      
    s中二分搜索出 
     
      
       
       
         x 
        
       
         − 
        
       
         t 
        
       
         o 
        
        
        
          t 
         
        
          2 
         
        
       
      
        x-tot_2 
       
      
    x−tot2的值,如果 
     
      
       
       
         x 
        
       
         − 
        
       
         t 
        
       
         o 
        
        
        
          t 
         
        
          2 
         
        
       
      
        x-tot_2 
       
      
    x−tot2存在,就是找到可行方案了,It’s MYGO!, 就把 
     
      
       
       
         t 
        
       
         y 
        
       
         p 
        
       
         e 
        
       
         [ 
        
       
         x 
        
       
         − 
        
       
         t 
        
       
         o 
        
        
        
          t 
         
        
          2 
         
        
       
         ] 
        
       
      
        type[x-tot_2] 
       
      
    type[x−tot2]加到最终答案 
     
      
       
       
         a 
        
       
         n 
        
       
         s 
        
       
      
        ans 
       
      
    ans中。
如果没有找到,就不是可行方案,乐队就要解散了(大悲)。
关于我曲折的debug过程
最开始是 
     
      
       
       
         T 
        
       
         L 
        
       
         E 
        
       
      
        TLE 
       
      
    TLE,这很正常,毕竟 
     
      
       
       
         s 
        
       
      
        s 
       
      
    s规模还是挺大的,硬搜肯定会 
     
      
       
       
         T 
        
       
      
        T 
       
      
    T掉。
 显然优化就是 
     
      
       
       
         u 
        
       
         n 
        
       
         i 
        
       
         q 
        
       
         u 
        
       
         e 
        
       
      
        unique 
       
      
    unique去重,然后统计 
     
      
       
       
         s 
        
       
      
        s 
       
      
    s每个元素的出现次数。
 结果还是过不了,一堆 
     
      
       
       
         W 
        
       
         A 
        
       
      
        WA 
       
      
    WA。
 心态就彻底炸了
 这题都做不出来是不是该速速remake了
 胃疼头疼的debuff就一起上了。
 最后发现,是 
     
      
       
       
         u 
        
       
         n 
        
       
         i 
        
       
         q 
        
       
         u 
        
       
         e 
        
       
      
        unique 
       
      
    unique写错了…
 本来我定义的 
     
      
       
       
         s 
        
       
      
        s 
       
      
    s大小是 
     
      
       
       
         c 
        
       
         n 
        
       
         t 
        
       
      
        cnt 
       
      
    cnt,实际我给写成 
     
      
       
       
         n 
        
       
      
        n 
       
      
    n了…
无话可说。。。。总之最后是过了,还算不错
完整代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e6+60;
long long si[maxn];
int cnt,n;
long long a[50],goal;
long long tot1=0,tot2=0;
long long minn;
long long type[maxn];
int len=0;
void dfs1(int x)
{
	if(x==n/2+1)
	{
		si[++cnt]=tot1;
		return;
	}
	tot1+=a[x];
	if(tot1<=goal) dfs1(x+1);
	tot1-=a[x];
	dfs1(x+1); 
}
long long ans=0;
int ans_id=0;
bool jud(long long res)
{
	int l=1,r=len;
	while(l<r)
	{
		int mid=(l+r+1)>>1;
		if(si[mid]==res)
		{
			ans_id=mid;
			return true;
		}
		if(si[mid]<=res) l=mid;
		else r=mid-1;
	}
	return false;/*
	for(int i=1;i<=cnt;++i) 
	{
		if(si[i]==res) ++ans;	
	}
	return false;*/
}
void dfs2(int x)
{
	if(x==n+1)
	{
		if(tot2==goal) ans+=type[1];
		else if(jud(goal-tot2)) ans+=type[ans_id];
		return;
	}
	tot2+=a[x];
	if(tot2+minn<=goal) dfs2(x+1);
	tot2-=a[x];
	dfs2(x+1);
}		
int main()
{
	scanf("%d%lld",&n,&goal);
	for(int i=1;i<=n;++i)  scanf("%lld",&a[i]);
	dfs1(1);
	minn=si[1];
	for(int i=2;i<=cnt;++i) minn=min(minn,si[i]);
	sort(si+1,si+cnt+1);
	long long now=si[1];
	long long cnt_now=1;
	len=0;
	for(int i=2;i<=cnt;++i)
	{
		if(si[i]==now) ++cnt_now;
		else
		{
			type[++len]=cnt_now;
			now=si[i];
			cnt_now=1;	
		}
	}
	type[++len]=cnt_now;
	unique(si+1,si+cnt+1)-si-1;
	dfs2(n/2+1);
	printf("%lld\n",ans);
//	printf("len=%d\n",len);
//	for(int i=1;i<=len;++i) printf("%d ",type[i]);
	return 0;	
}
/*
4 2
1 1 1 1
*/
题都看完了,就来推一首MYGO翻唱吧
【歌ってみた】少女レイ(少女REI) covered by 燈
一首不够?再来一个吧
【歌ってみた】「二息歩行 (Reloaded)」covered by 燈










