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. vue-router 重定向

    1.从 /a 重定向到 /b const router = new VueRouter({ routes: [ { path: '/a', redirect: '/b' } ] }) 重定向的目标也可 ...

  2. Codeforces 463C Gargari and Bishops 题解

    题目出处: http://codeforces.com/contest/463/problem/C 感觉本题还是挺难的.须要好好总结一下. 计算对角线的公式: 1 右斜对角线,也叫主对角线的下标计算公 ...

  3. 为什么 Linux 的 htop 命令完胜 top 命令

    在 Linux 系统中,top 命令用来显示系统中正在运行的进程的实时状态,它显示了一些非常有用的信息,比如 CPU 利用情况.内存消耗情况,以及每个进程情况等.但是,你知道吗?还有另外一个命令行工具 ...

  4. java 页面错误转发提示页面 errorPage转跳报HTTP500内部服务器错误

    errorPage和isErrorPage本来是很简单的功能,但是我却没弄出来,还百度了半天,结果发现是IE的设置问题.将下图中的“Show friendly HTTP error messages( ...

  5. 1 android 人脸识别

    1 https://www.google.com.hk/search?newwindow=1&safe=strict&q=android+%E5%9B%BE%E7%89%87%E4%B ...

  6. matlab-非线性方程求根函数及函数曲线绘制

    Matlab中提供了很多求解非线性方程(y=f(x))的函数,刚開始使用,真的很困惑.全部.这里依据matlab的help文档对这些函数做一些小小的总结 fsolve函数 用来求解非线性方程组:F(x ...

  7. mysql临时表空间暴涨

    (此文刚好遇到转载记录) 一.内部临时表使用 在某些情况下,服务器在处理语句时创建内部临时表,而用户无法直接控制临时表何时发生,完全有MySQL内部自行决定. MySQL在以下几种情况会创建临时表: ...

  8. 【HDU 5316】Magician(线段树)

    一開始度错题了,题意是求一段和最大的[子序列],要求相邻两个元素的位置必须互为奇偶. 这样我们能够使用线段树维护4个值: 一段区间内开头结尾元素为: 奇奇 奇偶 偶奇 偶偶 的最大值 之后在pushu ...

  9. C# 接口中的索引器

    索引器可在 接口(C# 参考) 上声明.接口索引器的访问器与类索引器的访问器具有以下方面的不同: 接口访问器不使用修饰符. 接口访问器没有体. 因此,访问器的用途是指示索引器是读写.只读还是只写.以下 ...

  10. spark+kafka 小案例

    (1)下载kafka的jar包 http://kafka.apache.org/downloads spark2.1 支持kafka0.8.2.1以上的jar,我是spark2.0.2,下载的kafk ...