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. 联想Y430P CentOS 7.3 无线网络的配置

    # uname -a # 查看内核/操作系统/CPU信息的Linux系统信息命令 [root@www ~]# uname -a Linux www SMP Tue Nov :: UTC x86_64 ...

  2. 简易高重用的jdbcutils工具封装实现类以及简易连接池实现

    因为如今发现做个小项目都是导入n多的依赖包,非常烦琐,仅仅想快点开发完一个个的小需求项目,这个时候真心不想用框架,仅仅能自己写个jdbcutils,尽管网上有非常多有apache的,阿里的,可是感觉用 ...

  3. Python——五分钟理解元类(metaclasses)

    “元类的魔幻变化比 99% 的用户所担心的更多,当你搞不懂是否真的需要用它的时候,就是不需要.” —Tim Peters 本文源于在 PyCon UK 2008 上的一个快速演讲. 元类被称为 Pyt ...

  4. React Native 爬坑之路

    1.react 基础 (创建组件及在浏览器上渲染组件) <!DOCTYPE html> <html lang="en"> <head> < ...

  5. 偶遇 smon 进程cpu 开销高异常分析

    今天突然发现线上一台oracle 数据库 servercpu 跑的非常高.感觉不是非常正常,细致看了下.发现是smon 进程吃掉了一个cpu. 那么这个smon 进程究竟在倒腾啥玩意 对smon 进程 ...

  6. TELNET模拟HTTP请求

    开启nginx服务,查看服务器地址(192.168.11.119) 使用telnet命令连接服务器的80端口 http协议报文格式 1.request 2.response 输入请求行: GET / ...

  7. STL学习笔记(已序区间算法)

    针对已序区间执行的算法,执行前提是源区间必须在某个排序准则下已序. 搜寻元素(Searching) 1.检查某个元素是否存在 bool binary_search(ForwardIterator be ...

  8. SQL Server 中树形表数据的处理总结

    -- 使用函数的方法: --建立 演示环境 if object_id('tb_bookInfo') is not null drop table tb_bookInfo go ),type int) ...

  9. shell 判断问题总结

    #!/bin/bash #比如需要判断一个变量是否含有值: if [[ -z $1 ]] ; thenecho "Something like empty!"exit 0;fi # ...

  10. Squid 启动/停止/重载配置文件 命令

    当你的 squid.conf 配置文档按照你的想法修改完以后,启动 squid 之旅就开始了. Squid安装设试命令: 1,初始化你在 squid.conf 里配置的 cache 目录 #/usr/ ...