[折半搜索]三教

题目描述  
三教是第三教学楼的简称,也是由虚幻工作室开发的一款恐怖推理游戏,将在 2020 年一月在 Steam 上
推出第一个 Demo。
Kanade 正控制着人物玩着满是 bug 的偷跑版。在游戏中,一共有 n  个补给点,如果人物到达补给点
,将会获得体力 ai ,但是如果在这个补给点用一些操作触发 bug,将会获得体力 2^f(ai) ,其中 f(x) 表
示  x 的二进制表示中 1的个数,最牛的 bug 莫过于到达补给点之后你可以选择不要提供的体力,也就
是操作之后玩家将不会获得任何体力,Kanade 也掌握了这个 bug 的触发方法。
因为之后要对战 boss,因此要收集足够的体力,但是如果打过 boss 并且剩了体力就无法触发后续剧
情,所以要求收集体力恰好为 X。Kanade 可以随心所欲地触发或不触发任意补给点的任何 bug,请问
她有多少种方式能够在全部走完这 n 个补给点后收集到 X体力。

输入
从  building.in  中读入以下内容:
第一行两个非负整数n,X  ,表示补给点个数和需要收集的体力数;
第二行 n 个非负整数  ai,第  i 个整数表示在不触发 bug 的情况下补给点 i  提供的体力。
输出
输出到  building.out。
输出一行一个整数,表示收集到 X 体力的方法数。

对于 60% 的数据,1<=n<=10 ;
对于 100%  的数据,1<=n<=25,1<=X,ai<=1e13 。

Solution 

折半搜索

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<map>
 4 using namespace std;
 5 const int N=30;
 6 int n; long long X,ans,a[N],f[N];
 7 inline int cal(long long x)
 8   {int cnt=0;
 9    while(x) x=(x&(x-1)),cnt++;
10    return cnt;
11   }
12 map<long long,long long> s;
13  void dfs(int i,long long x)
14   {if(x>X)   return;
15   
16    if(i>n/2) {s[x]++; return ;}
17    dfs(i+1,x); dfs(i+1,x+a[i]); dfs(i+1,x+f[i]);
18   }
19 void hehe(int i,long long x)
20   {if(x>X)   return;
21    if(i>n) {ans=ans+s[X-x];return ;}
22    hehe(i+1,x); hehe(i+1,x+a[i]); hehe(i+1,x+f[i]);
23   }  
24 int main()
25  {
26    scanf("%d%lld",&n,&X);
27   for(int i=1;i<=n;i++) {scanf("%lld",&a[i]);  f[i]=(1ll<<cal(a[i])); }
28   dfs(1,0); hehe(n/2+1,0);
29   printf("%lld",ans);
30  return 0;
31  }

 

posted @ 2019-11-12 07:57  YuXiaoze  阅读(195)  评论(0编辑  收藏  举报