首先,Hash Killer I、II、III是BZOJ上面三道很经典的字符串哈希破解题。当时关于II,本人还琢磨了好久,但一直不明白为啥别人AC的代码都才0.3kb左右,直到CYG神犇说可以直接随机水过去,遂恍然大悟。。。

于是,本人今天也做了下实验——假设现在有一个字符串题:输入N,接下来N行输入N个长度一样的由大写字母组成的字符串,求一共有多少种不同的字符串。此题有些类似于Hash Killer上面的原题。首先分析此题本身,两种常规办法:1.建立一棵字典树,然后可以相当方便快捷的判重,对于字符串长度均为M的数据,复杂度O(NM)  2.字符串哈希,选取一对质数pa和pb,哈希值为Sigma((ord(s1[i])-64)*pa^i) mod pb,然后通过哈希值排个序完事

接下来开始——字典树肯定能保证正确这个毫无疑问,但是更加毫无疑问的是哈希是相当容易被卡掉的(HansBug:尤其像Hash Killer II这样素数的神选取我也是醉了),但更加更加毫无疑问的是双取模哈希似乎还比较小强,于是我就此展开实验

1.写出一个数据生成器,负责随机生成N个长度为M的大写字母字符串,然后立刻用Trie树求出答案作为标准输出数据

  1. type
  2. point=^node;
  3. node=record
  4. ex:longint;
  5. next:array['A'..'Z'] of point;
  6. end;
  7. var
  8. i,j,k,l,m,n,ans:longint;
  9. head:point;
  10. s1,s2:ansistring;
  11. function getpoint:point;inline;
  12. var p:point;c1:char;
  13. begin
  14. new(p);p^.ex:=;
  15. for c1:='A' to 'Z' do p^.next[c1]:=nil;
  16. exit(p);
  17. end;
  18. function check(s1:ansistring):longint;inline;
  19. var i:longint;p:point;
  20. begin
  21. p:=head;
  22. for i:= to length(s1) do
  23. begin
  24. if p^.next[s1[i]]=nil then
  25. p^.next[s1[i]]:=getpoint;
  26. p:=p^.next[s1[i]];
  27. end;
  28. if p^.ex= then
  29. begin
  30. inc(ans);
  31. p^.ex:=ans;
  32. end;
  33. exit(p^.ex);
  34. end;
  35. begin
  36. readln(n,m);
  37. head:=getpoint;ans:=;
  38. RANDOMIZE;
  39. assign(output,'hs.in');
  40. rewrite(output);
  41. writeln(n);
  42. for i:= to n do
  43. begin
  44. s1:='';
  45. for j:= to m do s1:=s1+chr(random()+);
  46. writeln(s1);
  47. check(s1);
  48. end;
  49. close(output);
  50. assign(output,'hss.out');
  51. rewrite(output);
  52. writeln(ans);
  53. close(output);
  54. end.

2.接下来,开始写哈希,也不难,而且代码貌似还略短(这里面两个素数采用互换使用的模式,本程序是双取模的哈希,如果需要改成单值哈希的话直接把第50行去掉即可)

  1. const pa=;pb=;
  2. var
  3. i,j,k,l,m,n:longint;
  4. ap,bp:array[..] of int64;
  5. a:array[..,..] of int64;
  6. a1,a2,a3,a4:int64;
  7. s1,s2:ansistring;
  8. function fc(a1,a2,a3,a4:int64):longint;inline;
  9. begin
  10. if a1<>a3 then
  11. if a1>a3 then exit() else exit(-)
  12. else
  13. if a2<>a4 then
  14. if a2>a4 then exit() else exit(-)
  15. else exit();
  16. end;
  17. procedure sort(l,r:longint);
  18. var i,j:longint;x,y,z:int64;
  19. begin
  20. i:=l;j:=r;x:=a[(l+r) div ,];y:=a[(l+r) div ,];
  21. repeat
  22. while fc(a[i,],a[i,],x,y)=- do inc(i);
  23. while fc(x,y,a[J,],a[J,])=- do dec(j);
  24. if i<=j then
  25. begin
  26. z:=a[i,];a[i,]:=a[j,];a[j,]:=z;
  27. z:=a[i,];a[i,]:=a[j,];a[j,]:=z;
  28. inc(i);dec(j);
  29. end;
  30. until i>j;
  31. if i<r then sort(i,r);
  32. if l<j then sort(l,j);
  33. end;
  34.  
  35. begin
  36. ap[]:=;bp[]:=;
  37. for i:= to do
  38. begin
  39. ap[i]:=(ap[i-]*pa) mod pb;
  40. bp[i]:=(bp[i-]*pb) mod pa;
  41. end;
  42. readln(n);
  43. for i:= to n do
  44. begin
  45. readln(s1);
  46. a[i,]:=;a[i,]:=;
  47. for j:= to length(s1) do
  48. begin
  49. a[i,]:=(a[i,]+ap[j]*(ord(s1[j])-)) mod pb;
  50. a[i,]:=(a[i,]+bp[j]*(ord(s1[j])-)) mod pa; //删除此行即可改为单值哈希
  51. end;
  52. end;
  53. sort(,n);m:=;
  54. a[,]:=-maxlongint;
  55. for i:= to n do if fc(a[i-,],a[i-,],a[i,],a[i,])<> then inc(m);
  56. writeln(m);
  57. readln;
  58. end.

于是开始愉快的用bat来对拍:

1.当N=100000 M=3时,很令人吃惊——单双值的哈希都问题不大(随机跑了403组数据均全部通过)

2.当N=100000 M=100是,果不其然——单值的哈希成功而华丽的实现了0%的命中率,而双值的哈希依然100%(HansBug:实测6001组数据,跑了快两小时有木有啊啊啊啊 wnjxyk:What Ghost? HansBug:我家电脑渣不解释^_^)

(HansBug:呵呵哒BZOJ3098这题我居然上来就WA了,现在看来这究竟是什么样的神人品啊)

结果已经了然,而且从bat上运行的时间来看,当N=100000 M=100时,哈希的速度比trie树看样子明显快——估计是虽然trie树可以达到O(NM),但是假如需要新建大量的点的话,那样势必相当费时,多半慢在这上面了,而哈希就是该怎么玩怎么玩——更重要的是——哈希,绝对不等同于非得开一个巨大的数组瞎搞,比如这个例子中直接排个序就完事啦。更重要的是双值哈希的稳定性还是相当不错滴!!!^_^

后记:以前我曾经一度认为hash算法一定就是必然伴随着一个硕大的数组(HansBug:搞不好还MLE有木有TT  bx2k:那是必然),其实它的灵活性远远超出了我的预想,今天也算是大长了见识;还有祝愿BZOJ3099(Hash Killer III)永远不要有人AC!!!否则那就基本意味着哈希算法的终结了TT

附:对拍用的bat模板,纯手写的哦,如有雷同绝无可能么么哒

  1. @echo off
  2. set /a s=0
  3. :1
  4. set /a s=s+1
  5. echo Test %s%
  6. rem 此处两个数分别代表NM,手动修改下即可
  7. echo 10000 100|hs.exe
  8. copy hs.in hash\hs%s%.in >nul
  9. copy hsS.out hash\hs%s%.out >nul
  10. echo.|time
  11. type hash\hs%s%.in|hash.exe >hash\hs%s%.ou
  12. echo.|time
  13. fc hash\hs%s%.ou hash\hs%s%.out >hash\res%s%.txt
  14. fc hash\hs%s%.ou hash\hs%s%.out
  15. goto 1

从Hash Killer I、II、III论字符串哈希的更多相关文章

  1. 【BZOJ】 Hash Killer I II III

    前言 这里只是一个整理... Solution Hash Killer I Hash Killer II

  2. Hash Killer I II

    题意大概: 1.字符串hash不取模,自动溢出  构造数据卡这种hash 2.字符串hash取模1000000007,构造数据卡这种hash 题解传送门:VFleaKing http://vfleak ...

  3. 3097: Hash Killer I

    3097: Hash Killer I Time Limit: 5 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 425  Solved: 15 ...

  4. 3098: Hash Killer II

    3098: Hash Killer II Time Limit: 5 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 1219  Solved:  ...

  5. BZOJ 3098: Hash Killer II(新生必做的水题)

    3098: Hash Killer II Time Limit: 5 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 1555  Solved: ...

  6. BZOJ 3098 Hash Killer II

    3098: Hash Killer II Description 这天天气不错,hzhwcmhf神犇给VFleaKing出了一道题: 给你一个长度为N的字符串S,求有多少个不同的长度为L的子串. 子串 ...

  7. 【BZOJ3098】 Hash Killer II

    BZOJ3098 Hash Killer II Solution 这道题目好像题面里面给了提示(当然没给就有点难想了.) 曾经讲过一个叫做生日悖论的,不知道还有多少人记得 考虑相同的可能性大概是\(\ ...

  8. Leetcode 137. Single Number I/II/III

    Given an array of integers, every element appears twice except for one. Find that single one. 本题利用XO ...

  9. BZOJ 3097: Hash Killer I【构造题,思维题】

    3097: Hash Killer I Time Limit: 5 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 963  Solved: 36 ...

随机推荐

  1. Android常用开发工具的用法

    1.在命令行创建.删除和浏览AVD 在命令行下管理AVD需要借助于android命令(位于Android SDK安装目录的tools子目录下),如果直接执行android子命令将会启动Android ...

  2. Spring classPath:用法

    http://blog.csdn.net/xing_sky/article/details/8228305 参考文章地址: http://hi.baidu.com/huahua035/item/ac8 ...

  3. 在COM组件中调用JS函数

    要求是很简单的,即有COM组件A在IE中运行,使用JavaScript(JS)调用A的方法longCalc(),该方法是一个耗时的操作,要求通知IE当前的进度.这就要求使用回调函数,设其名称为scri ...

  4. doubango简介

    1.doubango官网:http://www.doubango.org/ doubango常用项目国内镜像(放在淘宝的svn服务器),目前有4个项目:doubango, idoubs, imsdro ...

  5. Ubuntu16.04安装GTK3主题:OSX-Arc

    Ubuntu16.04安装GTK3主题:OSX-Arc GTK3主题:OSX-Arc描述: 前几个月,Gnome3.20升3.22的时候,出现了大量主题崩溃的现象,其中包括Arc.Flatabulou ...

  6. [css]《css揭秘》学习(三)-灵活的背景定位

    一.background-position属性 使用该属性,在不确定容器大小的情况下,也可以指定图案距离容器边缘的位置:但是需要为不支持该属性的浏览器指定回退方案,否则,图案会默认放在左上角. < ...

  7. StringUtils工具类常用方法介绍(持续更新)

    StringUtils方法的操作对象是java.lang.String类型的对象,是JDK提供的String类型操作方法的补充,并且是null安全的(即如果输入参数String为null则不会抛出Nu ...

  8. [Direct2D1.1教程] Direct2D特效概览

    转载请注明出处:http://www.cnblogs.com/Ray1024 一.概述 Direct2D是一个基于Direct3D的2D图形API,可以利用硬件加速特性来提供高性能高质量的2D渲染.但 ...

  9. 持久层框架之MyBatis

    1.mybatis框架介绍: MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并 ...

  10. 自己动手系列——实现一个简单的ArrayList

    ArrayList是Java集合框架中一个经典的实现类.他比起常用的数组而言,明显的优点在于,可以随意的添加和删除元素而不需考虑数组的大小.处于练手的目的,实现一个简单的ArrayList,并且把实现 ...