前言

若干年前看过现在又忘了。这么简单都忘

所以今天来重新复习一下。

正题

考虑这样的问题:

给定 \(n\) 个物品的价格,你有 \(m\) 块钱,每件物品限买一次,求买东西的方案数。

\(n\leq 40\),\(m\leq 10^{18}\)。

在看到数据范围之前,所有人的想法都是直接背包,看到数据范围后就寄了。

看样子不可用背包,那就用搜索吧。

直观的,我们考虑 \(O(2^n\times n)\) 的做法。

用 \(O(2^n)\) 的复杂度枚举每个物品是否购买,再 \(O(n)\) 复杂度判断是否合法。

但是看懂 \(n \leq 40\) 时就又寄了。

这是我们考虑 meet in the middle ,把时间复杂度变成 \(O(2^{\frac{n}{2}}+合并复杂度)\) 。

我们直接把当前的物品分成 \(1\sim \frac{n}{2}\) 和 \(\frac{n}{2}+1 \sim n\) 两个部分。

对于每一个部分我们都进行搜索,并把当前方案的花费 分两个数组 记录下来。

不难发现,到这为止,时间复杂度是 \(O(n^{\frac{n}{2}})\) 带有 \(2\) 的常数。

考虑怎么处理计算出来的各种方案的花费。

先考虑其中一个数组中的一种花费必选,然后直接二分查找即可。

(当然,之前要对这两个数组进行排序)

Code

笔者远古代码,没有人肉格式化,不喜勿喷。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std; #define ll long long
#define re register
#define N 50
#define M 2000005 int max(ll a,ll b){return a>b?a:b;}
int min(ll a,ll b){return a<b?a:b;} int n,num,visit[N];
ll m,a[N],num1[M],num2[M];
ll b[N],c[N],ans=0; inline ll read(){
ll s=0,t=1;
char c=getchar();
while((c<'0'||c>'9')&&c!='-')c=getchar();
if(c=='-')c=getchar(),t=-1;
while(c>='0'&&c<='9')s=(s<<1)+(s<<3)+(c^48),c=getchar();
return s*t;
} void dfs_b(int k){
if(k>b[0]){
ll s=0;
for(int i=1;i<=b[0];i++)
if(visit[i]==1)s+=b[i];
num1[++num1[0]]=s;
return;
}
visit[k]=1;
dfs_b(k+1);
visit[k]=0;
dfs_b(k+1);
} void dfs_c(int k){
if(k>c[0]){
ll s=0;
for(int i=1;i<=c[0];i++)
if(visit[i]==1)s+=c[i];
num2[++num2[0]]=s;
return;
}
visit[k]=1;
dfs_c(k+1);
visit[k]=0;
dfs_c(k+1);
} ll find(ll need){
ll l=1,r=num2[0];
ll mid,maxn=0;
while(l<=r){
mid=(l+r)/2;
if(num2[mid]<=need){
maxn=max(maxn,mid);
l=mid+1;
}
else r=mid-1;
}
return maxn;
} int main(void){
scanf("%d",&n);
m=read();
for(int i=1;i<=n;i++)
a[i]=read();
num=n/2;
for(int i=1;i<=num;i++)
b[++b[0]]=a[i];
for(int i=num+1;i<=n;i++)
c[++c[0]]=a[i];
memset(visit,0,sizeof(visit));
dfs_b(1);
memset(visit,0,sizeof(visit));
dfs_c(1);
sort(num2+1,num2+1+num2[0]);
for(int i=1;i<=num1[0];i++){
ll now=m-num1[i];
if(now<0ll)continue;
ans+=find(now);
}
printf("%lld\n",ans);
}

meet in the middle 复习笔记的更多相关文章

  1. Meet in the middle学习笔记

    Meet in the middle(MITM) Tags:搜索 作业部落 评论地址 PPT中会讲的很详细 当搜索的各项互不影响(如共\(n\)个物品前\(n/2\)个物品选不选和后\(n/2\)个物 ...

  2. Java基础复习笔记系列 九 网络编程

    Java基础复习笔记系列之 网络编程 学习资料参考: 1.http://www.icoolxue.com/ 2. 1.网络编程的基础概念. TCP/IP协议:Socket编程:IP地址. 中国和美国之 ...

  3. Java基础复习笔记系列 八 多线程编程

    Java基础复习笔记系列之 多线程编程 参考地址: http://blog.csdn.net/xuweilinjijis/article/details/8878649 今天的故事,让我们从上面这个图 ...

  4. Java基础复习笔记系列 七 IO操作

    Java基础复习笔记系列之 IO操作 我们说的出入,都是站在程序的角度来说的.FileInputStream是读入数据.?????? 1.流是什么东西? 这章的理解的关键是:形象思维.一个管道插入了一 ...

  5. Java基础复习笔记系列 五 常用类

    Java基础复习笔记系列之 常用类 1.String类介绍. 首先看类所属的包:java.lang.String类. 再看它的构造方法: 2. String s1 = “hello”: String ...

  6. Java基础复习笔记系列 四 数组

    Java基础复习笔记系列之 数组 1.数组初步介绍? Java中的数组是引用类型,不可以直接分配在栈上.不同于C(在Java中,除了基础数据类型外,所有的类型都是引用类型.) Java中的数组在申明时 ...

  7. Java基础复习笔记基本排序算法

    Java基础复习笔记基本排序算法 1. 排序 排序是一个历来都是很多算法家热衷的领域,到现在还有很多数学家兼计算机专家还在研究.而排序是计算机程序开发中常用的一种操作.为何需要排序呢.我们在所有的系统 ...

  8. Meet in the middle

    搜索是\(OI\)中一个十分基础也十分重要的部分,近年来搜索题目越来越少,逐渐淡出人们的视野.但一些对搜索的优化,例如\(A\)*,迭代加深依旧会不时出现.本文讨论另一种搜索--折半搜索\((meet ...

  9. SPOJ4580 ABCDEF(meet in the middle)

    题意 题目链接 Sol 发现abcdef是互不相关的 那么meet in the middle一下.先算出abc的,再算def的 注意d = 0的时候不合法(害我wa了两发..) #include&l ...

随机推荐

  1. JavaScript函数中的arguments对象

    ECMAScript标准中,每个函数都有一个特殊的内置对象arguments.arguments对象是一个类Array对象(object),用以保存函数接收到的实参副本. 一.内置特性 说它是一个内置 ...

  2. Runable与Callable的区别

    Runable与Callable的区别: public interface Callable<V> { V call() throws Exception;//V是Callable返回值的 ...

  3. 前后端分离,简单JWT登录详解

    前后端分离,简单JWT登录详解 目录 前后端分离,简单JWT登录详解 JWT登录流程 1. 用户认证处理 2. 前端登录 3. 前端请求处理 4. 后端请求处理 5. 前端页面跳转处理 6. 退出登录 ...

  4. 4.27-Postman和JMeter总结及实战描述

    一.数据格式 常用的请求方法有8种,但是最常用的有4-5种 1.GET 获取资源 2.POST 添加资源(对服务端已存在的资源也可以做修改和删除操作) 3.PUT 修改资源 4 .DELETE删除资源 ...

  5. SDDC的Windows初体验-QT篇

    前言 如果熟悉爱智和看过我之前文章的朋友见到这篇文章一定会有很大疑问,SDDC 作为智能设备发现控制协议,怎么会用在 windows 上? 这一切还是源自于我巨大的脑洞,因为这段在搞 Windows ...

  6. 浅谈 Linux IO

    公众号关注 「开源Linux」 回复「学习」,有我为您特别筛选的学习资料~ 来源于:360云计算 1 前言 Linux IO是文件存储的基础.本文参考了网上博主的一些文章,主要总结了LinuxIO的基 ...

  7. RabbitMQ 3.9( 基础 )

    1.认识MQ 1.1.什么是MQ? MQ全称:message queue 即 消息队列 这个队列遵循的原则:FIFO 即 先进先出 队列里面存的就是message 1.2.为什么要用MQ? 1.2.1 ...

  8. jQuery前端第三方框架

    计时器 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8 ...

  9. http缓存策略以及强缓存和协商缓存浅析

    http缓存策略以及强缓存和协商缓存浅析 本地缓存-强缓存 本地缓存,也就是我们常说的强缓存:是指当浏览器请求资源时,如果请求服务端的资源命中了浏览器本地的缓存资源,那么浏览器就不会发送真正请求给服务 ...

  10. Unity-Adressable打包热更

    Addressable是Unity推出的打ab包方案,自动依赖: 不需要手动写AB打包方案,不需要关心依赖; 提供本地远程服务异步加载: 打包粒度可调节: 1.Group Addressable打包需 ...