Meeting-in-the-Middle,又称“中途相遇法”。准确地说,它只是一种策略。

顺便说一下,这个算法真的很冷门!

结合这道题来讨论一下吧:LA 2965。ε(┬┬﹏┬┬)3

因为博主的英文实在是十分拙劣,所以只能给出题目大意:

题目大概是说,输入多组数据(组数未知 反正不多啦),每组给定一个$k<=24$,代表有k个字符串。

然后每组的后k行,依次输入这么多个字符串。

要求你选择尽量多的字符串,使得被选的字符串中的所有字母中,每种字母都出现偶数次。

输出选择字符串数,并从小到大输出被选字符串。

给组样例吧:

in

ABC

ABD
EG
GE
ABE
AC
BCD

out


      

这个题目,乍一看上去,博主就只想到了模拟。。。(博主蒟蒻一枚)。

事实上,仔细分析,我们会发现:

这个题目,和字母的个数实际上没多大关系,更多的是和字母出现次数的奇偶有关。

于是我们假设有这么一张表:(拿样例中k=6的那一组为例)

A B C D E F G H……
……
……
……
……
……
…… 

代表什么呢?显然这个表上的每一行都是一个26为的二进制数,而每一位对应一个字母,代表这个字母在此串中出现次数的奇或偶。

1代表的是奇,0代表的是偶。

仔细想想,我们是不是只要这么做:选择尽量多的串,使其异或值为0。

好。有了这张表,这就好办了。我们可以进行暴力穷举法$O(2^n)$。是不是还是很low?显然,这个时间复杂度过不了规模高达24的数据。

那么,我们怎么办呢?

这时候,我们开始讲到的MITM策略就可以派上用场了。

别看它的名字这么高级,其实思想主要是:

将待测数据(也就是那张表)分成两部分,枚举上表的所有子集的xor值,放入一个hash表或者map映射里。

然后枚举后半部分的数据所能得到的所有xor值,并每次都在hash表或者map映射里查找。

如果用map实现的话,总时间复杂度为$O(2^{(n/2)}logn)$,即$O(1.414^nlogn)$,比第一种方法好了很多。

这就是Meeting-in-the-Middle中途相遇法。

据刘汝佳神犇所述:密码学中的著名的中途相遇攻击(Meeting-in-the-Middle attack)就是基于这个原理。

最后贴上代码吧:

#include <bits/stdc++.h>
using namespace std; const int maxn=;
map <int,int> table; int bitcount(int x) {
return x==?:bitcount(x/)+(x&);
}//这个函数用来计算这个数在二进制下有多少个1 int main()
{
int n,A[maxn];
char s[];
while (scanf("%d",&n)==&&n) {//读入多组数据
for (int i=;i<n;i++) {
scanf("%s",s);//输入字符串
A[i]=;
for (int j=;s[j]!='\0';j++)
A[i]^=(<<(s[j]-'A'));//计算每一串的<=26位二进制值
}
table.clear();//清空table映射
int n1=n/,n2=n-n1;//将待测数据分成两部分 //接下来循环计算2^(n/2)个属于前半部分的子集
for (int i=;i<(<<n1);i++) {
int x=;
for (int j=;j<n1;j++)
if (i&(<<j)) x^=A[j];
if (!table.count(x)||bitcount(table[x])<bitcount(i))
table[x]=i;
}//取每个计算结果中的最大值 //最后处理后半部分
int ans=;
for (int i=;i<(<<n2);i++) {
int x=;
for (int j=;j<n2;j++)
if (i&(<<j)) x^=A[n1+j];
if (table.count(x)&&bitcount(ans)<bitcount(table[x])+bitcount(i))
ans=(i<<n1)^table[x];
}//每次计算前查找映射中是否出现过
printf("%d\n",bitcount(ans));
for (int i=;i<n;i++)
if (ans&(<<i)) printf("%d ",i+);
printf("\n");//输出部分
}
return ;
}

如果不用map也可以改成哈希(hash):

int insHash(int x)
{
int c=x%MOD;
for (int u=h[c];u;u=nexp[u])
if (val[u]==x) return u;
if (!gans)
nexp[p]=h[c],h[c]=p,val[p]=x,p++;
return -(p-);
}

然后听机房一位神犇说,这题用深搜(dfs)枚举子集会更快,虽然不知为何?

void dfs(int f,int sum,int k)
{
if (f>upb){
if (sum==-) return;
x=insHash(sum);
if (!gans) {
if (x<) x=-x;
if (k>cnt[x]) cnt[x]=k;
}
else if (x>&&cnt[x]+k>ans)
ans=cnt[x]+k;
else if (!sum&&k>ans) ans=k;
return;
}
dfs(f+,sum==-?num[f]:sum^num[f],k+);
dfs(f+,sum,k);
}

Meeting-in-the-Middle (LA 2965)的更多相关文章

  1. LA 2965 Jurassic Remains

    这是我做的第一道状态压缩的题目,而且我自己居然看懂了,理解得还算透彻. 题意:给出若干个大写字母组成的字符串,然后选取尽量多的字符串使得这些字母出现偶数次. 最朴素的想法,穷举法:每个字符串只有选和不 ...

  2. LA 2965 Jurassic Remains (中途相遇法)

    Jurassic Remains Paleontologists in Siberia have recently found a number of fragments of Jurassic pe ...

  3. UVa LA 2965 - Jurassic Remains 中间相遇,状态简化 难度: 2

    题目 https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_pr ...

  4. LA 2965 中途相遇法

    题目链接:https://vjudge.net/problem/UVALive-2965 题意: 有很多字符串(24),选出一些字符串,要求这些字符串的字母都是偶数次: 分析: 暴力2^24也很大了, ...

  5. 【中途相遇+二进制】【NEERC 2003】Jurassic Remains

    例题25  侏罗纪(Jurassic Remains, NEERC 2003, LA 2965) 给定n个大写字母组成的字符串.选择尽量多的串,使得每个大写字母都能出现偶数次. [输入格式] 输入包含 ...

  6. 暑期培训7日游解题思路(day1~day3)

    暑期培训7日游解题思路(day1~day3) day1 第一天,王聿中老师出的题目比较简单,T1很水,T2是个简单的DP,T3还是有一点意思的.在网格图中删掉若干条边,使得所有格子都联通,求删掉的边的 ...

  7. SPOJ11469 SUBSET

    题面 Farmer John's owns N cows (2 <= N <= 20), where cow i produces M(i) units of milk each day ...

  8. UVALive - 2965 Jurassic Remains (LA)

    Jurassic Remains Time Limit: 18000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu [Sub ...

  9. Technical Committee Weekly Meeting 2016.06.21

    Meeting time: 2016.June.21 1:00~2:00 Chairperson:  Thierry Carrez Meeting summary: 1.Add current hou ...

随机推荐

  1. Effective C++--经验条款

    高效C++ --模板与泛型编程 在C++中模板体现的是编译期多态,virtual体现的是执行期多态. 关于typename的双重含义: 在声明template參数时,不论使用keywordclass或 ...

  2. 使用Jenkins+Calabash+Cocoapods搭建iOS持续集成环境

    使用jenkins+calabash+cocoapods搭建ios持续集成环境 持续集成 持续集成到底是什么呢?依据敏捷大师Martin Fowler的定义: 持续集成是一种软件开发实践. 在持续集成 ...

  3. 100多道经典的JAVA面试题及答案解析

    面向对象编程(OOP) Java是一个支持并发.基于类和面向对象的计算机编程语言.下面列出了面向对象软件开发的优点: 代码开发模块化,更易维护和修改. 代码复用. 增强代码的可靠性和灵活性. 增加代码 ...

  4. Nginx限制连接和请求

    一.ngx_http_limit_conn_module对同一个ip/server的连接数做限制.配置指令:limit_conn_zone语法: limit_conn_zone $variable z ...

  5. Linux组件封装(五)一个生产者消费者问题示例

    生产者消费者问题是计算机中一类重要的模型,主要描述的是:生产者往缓冲区中放入产品.消费者取走产品.生产者和消费者指的可以是线程也可以是进程. 生产者消费者问题的难点在于: 为了缓冲区数据的安全性,一次 ...

  6. 通过mysql show processlist 命令检查mysql锁的方法

    作者: 字体:[增加 减小] 类型:转载 时间:2010-03-07 show processlist 命令非常实用,有时候mysql经常跑到50%以上或更多,就需要用这个命令看哪个sql语句占用资源 ...

  7. 如何创建JAR文件?如何运行.jar形式的Java程序?

    一.如何创建JAR文件? .jar是用来压缩档案或者解压档案的文件格式,其特点是具有无损压缩的功能.想知道如何创建这种程序?请访问 http://www.cnblogs.com/yjmyzz/p/ex ...

  8. nightwatch API

    API Nightwatch的API分为四个部分 1.Expect 在browser实例上以.expect.element开头的BDD(行为驱动测试)风格的接口,0.7及以上版本nightwatch可 ...

  9. 使用spring-boot-admin对spring-boot服务进行监控(转自牛逼的人物)

    尊重原创:http://www.cnblogs.com/ityouknow/p/8440455.html 上一篇文章<springboot(十九):使用Spring Boot Actuator监 ...

  10. webpack 功能大全 【环境配置】

    1. webpack简介 webpack 是一个模块打包工具.它使得模块相互依赖并且可构建等价于这些模块的静态资源.相比于已经存在的模块打包器(module bundler),webpack的开发动机 ...