不懂hash是什么的盆友给出直通车:滴滴滴,开车啦~

如果你看懂了的话:

hash模板来也~

#include <cstdio>
#include <string>
#include <iostream>
#include <algorithm> using namespace std; typedef long long LL; const int N = 1e5 + ; //
const int D = ; //质数
const int MD = 1e9 + ; //大质数 int n;
string s; unsigned long long f[N], g[N]; //g[i]为D的i次方 void prehash(int n) //进行预处理
{
// 预处理时,注意到数字可能很大,对一个数 MD 取模
f[] = s[];//预处理前缀和(进行强制类型转)
for(int i=; i<=n; i++)
f[i] = (1LL * f[i-] * D + s[i-]) % MD; g[] = ; //预处理D
for(int i=; i<=n; i++)
g[i] = 1LL * g[i-] * D % MD;
} int hash(int l, int r) //计算区间 [l,r] 的哈希值
{
int a = f[r];
int b = 1LL * f[l-] * g[r-l+] % MD; return (a - b + MD) % MD; //+MD是为了防止出现负数
} int main()
{
cin >> s;
n = s.length();
prehash(n); while(!cin.eof())//直至按ctrl+z键退出!
{
int l, r;
cin >> l >> r;
cout << s.substr(l-, r-l+) << ": " << hash(l, r) << endl;
//从l-1到r-l+1的字符
} return ;
}

良心推荐洛谷练手题:

1.P3370【模板】字符串哈希

题目描述

如题,给定N个字符串(第i个字符串长度为Mi,字符串内包含数字、大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串。

友情提醒:如果真的想好好练习哈希的话,请自觉,否则请右转PJ试炼场:)

输入输出格式

输入格式:

第一行包含一个整数N,为字符串的个数。

接下来N行每行包含一个字符串,为所提供的字符串。

输出格式:

输出包含一行,包含一个整数,为不同的字符串个数。

输入输出样例

输入样例#1:

5
abc
aaaa
abc
abcc
12345
输出样例#1:

4

说明

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=10,Mi≈6,Mmax<=15;

对于70%的数据:N<=1000,Mi≈100,Mmax<=150

对于100%的数据:N<=10000,Mi≈1000,Mmax<=1500

样例说明:

样例中第一个字符串(abc)和第三个字符串(abc)是一样的,所以所提供字符串的集合为{aaaa,abc,abcc,12345},故共计4个不同的字符串。

Tip: 感兴趣的话,你们可以先看一看以下三题:

BZOJ3097:http://www.lydsy.com/JudgeOnline/problem.php?id=3097

BZOJ3098:http://www.lydsy.com/JudgeOnline/problem.php?id=3098

BZOJ3099:http://www.lydsy.com/JudgeOnline/problem.php?id=3099

如果你仔细研究过了(或者至少仔细看过AC人数的话),我想你一定会明白字符串哈希的正确姿势的^_^

思路:

  题解里面是有很多种方法的,但是我认为能够搞懂一种就已经很不错了……

  所以我给出的思路就是用set来进行统计,set只能够允许一种数字出现一次,所以我们就可以将给出的字符串的hash值求出来

  然后加入到set里面,最后直接输出set里面有多少数就行啦~

PS:

      定义函数的时候不要用"hash"这个名字,在洛谷里是关键字!!!

上代码=u=:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
#include <set> using namespace std; typedef unsigned long long ull;
typedef long long LL;
set<ull>ssr; const int N = ;
const int D = ; //质数
const ull MD= 1e9 + ; //大质数 LL n,len;
string s; ull f[N];//预处理前缀和
ull g[N];//预处理 D的i次方 int yuchuli(int q)
{
memset(f,,sizeof(f));
memset(g,,sizeof(g));
f[]=s[];
for(int i=;i<=q;i++)
f[i] = (1LL * f[i-] * D +s[i-]) % MD;
g[]=;
for(int i=;i<=q;i++)
g[i] = 1LL * g[i-] * D % MD;
} int hashs(int l,int r)
{
ull a = f[r];
ull b = 1LL * f[l-] *g[r-l+] % MD; return (a - b + MD) % MD;
} int main()
{
cin>>n;
while(n--)
{
cin>>s;
len=s.length();
yuchuli(len);
ull qq = hashs(,len);
ssr.insert(qq);
}
cout<<ssr.size();
return ;
}  

2.

cogs249. [POI2000] 最长公共子串

★★★   输入文件:pow.in   输出文件:pow.out   简单对比
时间限制:1 s   内存限制:256 MB

给出几个由小写字母构成的单词,求它们最长的公共子串的长度。

任务

  • 从文件中读入单词
  • 计算最长公共子串的长度
  • 输出结果到文件

输入

文件的第一行是整数 n,1<=n<=5,表示单词的数量。接下来n行每行一个单词,只由小写字母组成,单词的长度至少为1,最大为2000。

输出:

仅一行,一个整数,最长公共子串的长度。

样例输入:

3
abcb
bca
acbc

样例输出:

2

 思路:

  正解据说是后缀数组呢!后缀数组是什么鬼???我又不会...只好胡乱搞hash啦~结果一搞...奇迹的就WA了一个点,结果又胡乱改了一下Mod,然后就A了...真不可思议w

    Ps:脑洞产物(正解xxx),能不能过全看 your rp!!!

  话不多说:

  hash的思路:

  •       pre:

          首先话不多说,跟普通hash一样把每一个单词的hash值求一下,然后快乐地开始进行二分公共子串的长度

          然后我们又设置了vis和times两个数组,其中times[i]表示当前hash值i已经出现在几个单词里面。
          接着枚举每个单词中子串的开始位置,用O(1)时间求该子串的hash,然后times加一。
          (当然同一个长单词里面可能有相同的子串,所以用vis记录一下这个hash值最后出现在第几个单词中,来判断该子串在当前字符串中是不是第一次出现。)
  •       结束条件:
          如果times加到n了,说明每个单词里面都有这个子串,这个解是正确的,然后顺路更新一下ans的值!
  •       时间复杂度:
          1)求hash是O(|S|*n),|S|表示最长的子串长度。
          2)二分答案部分为(log|S|*n*|S|)。
        故总体的期望复杂度为O(log|S|*|S|*n),而n只有5,|S|只有2000,显然轻松过去..
        over!!!

坑点:

  在选取Mod以及D的时候,一定要多用几组,防止发生冲突。

上代码=v=:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#define INF 0x7fffffff
#define LL long long
using namespace std; const int D = ;
const int Mod = ;
const int N = ;
const int le = ;
int n,minl,ans;
LL f[N][le],g[le];
int len[N];
char str[le];
int vis[Mod+],times[Mod+]; bool check(int x)
{
memset(vis,,sizeof(vis));
memset(times,,sizeof(times));
LL cv=g[x];
for(int i=;i<=n;++i)
{
for(int j=x;j<=len[i];++j)
{
LL nowhash=(f[i][j]-(f[i][j-x]*cv)%Mod+Mod)%Mod;
if(vis[nowhash]!=i)
{
++times[nowhash];
vis[nowhash]=i;
if(times[nowhash]==n)
return true;
}
}
}
return false;
} void prehash(int i)
{
f[i][]=str[]-'a'+;
for(int j=;j<=len[i];++j)
f[i][j]=(f[i][j-]*D+(str[j-]-'a'+))%Mod;
} void dichotomy()
{
int l=,r=minl+;
while(l<r)
{
int mid=(l+r)>>;
if(check(mid))
ans=mid,l=mid+;
else
r=mid;
}
printf("%d",ans);
} int main()
{
freopen("pow.in", "r", stdin);
freopen("pow.out", "w", stdout);
scanf("%d",&n);
minl=INF;
for(int i=;i<=n;++i)
{
scanf("%s",str);
len[i]=strlen(str);
if(len[i]<minl) minl=len[i];
prehash(i);
}
g[]=;
for(int i=;i<=minl;++i)
g[i]=1LL*g[i-]*D%Mod;
dichotomy();
return ;
}

【テンプレート】字符串hash的更多相关文章

  1. [知识点]字符串Hash

    1.前言 字符串的几大主要算法都多少提及过,现在来讲讲一个称不上什么算法, 但是非常常用的东西——字符串Hash. 2.Hash的概念 Hash更详细的概念不多说了,它的作用在于能够对复杂的状态进行简 ...

  2. 【BZOJ-3555】企鹅QQ 字符串Hash

    3555: [Ctsc2014]企鹅QQ Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1545  Solved: 593[Submit][Statu ...

  3. POJ 1200 字符串HASH

    题目链接:http://poj.org/problem?id=1200 题意:给定一个字符串,字符串只有NC个不同的字符,问这个字符串所有长度为N的子串有多少个不相同. 思路:字符串HASH,因为只有 ...

  4. LA4671 K-neighbor substrings(FFT + 字符串Hash)

    题目 Source http://acm.hust.edu.cn/vjudge/problem/19225 Description The Hamming distance between two s ...

  5. 各种字符串Hash函数比较(转)

    常用的字符串Hash函数还有ELFHash,APHash等等,都是十分简单有效的方法.这些函数使用位运算使得每一个字符都对最后的函数值产生影响.另外还有以MD5和SHA1为代表的杂凑函数,这些函数几乎 ...

  6. 字符串hash + 二分答案 - 求最长公共子串 --- poj 2774

    Long Long Message Problem's Link:http://poj.org/problem?id=2774 Mean: 求两个字符串的最长公共子串的长度. analyse: 前面在 ...

  7. 字符串hash - POJ 3461 Oulipo

    Oulipo Problem's Link ---------------------------------------------------------------------------- M ...

  8. 长度有限制的字符串hash函数

    长度有限制的字符串hash函数 DJBHash是一种非常流行的算法,俗称"Times33"算法.Times33的算法很简单,就是不断的乘33,原型如下 hash(i) = hash ...

  9. hdu 4622 Reincarnation 字符串hash 模板题

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4622 题意:给定一个长度不超过2000的字符串,之后有不超过1e5次的区间查询,输出每次查询区间中不同 ...

  10. [转]各种字符串Hash函数比较

    转自:https://www.byvoid.com/zht/blog/string-hash-compare 常用的字符串Hash函数还有ELFHash,APHash等等,都是十分简单有效的方法.这些 ...

随机推荐

  1. 手工给程序插入 ShellCode

    PE格式是 Windows下最常用的可执行文件格式,理解PE文件格式不仅可以了解操作系统的加载流程,还可以更好的理解操作系统对进程和内存相关的管理知识,而有些技术必须建立在了解PE文件格式的基础上,如 ...

  2. [Luogu5327][ZJOI2019]语言(树上差分+线段树合并)

    首先可以想到对每个点统计出所有经过它的链的并所包含的点数,然后可以直接得到答案.根据实现不同有下面几种方法.三个log:假如对每个点都存下经过它的链并S[x],那么每新加一条路径进来的时候,相当于在路 ...

  3. vs2015工程转化为vs2010

    转换的步骤如下: (1)将工程是.sln用记事本打开后,更换以下信息如下:   Microsoft Visual Studio Solution File, Format Version 11.00 ...

  4. solr的post.jar

    http://iamyida.iteye.com/blog/2207920   跟益达学Solr5之玩转post.jar

  5. iOS - UIWebView和WKWebView的比较和选择-作为H5容器的一些探究

    一.Native开发中为什么需要H5容器 Native开发原生应用是手机操作系统厂商(目前主要是苹果的iOS和google的Android)对外界提供的标准化的开发模式,他们对于native开发提供了 ...

  6. js入门之对象

    一.对象理解 现实世界 万物皆对象, 一切事物都是对象 对象还是一个具体的事物 对象: 特征和行为组成 特征是名词 用来描述对象的, 行为是动词 程序中的对象 是对现实世界中事物的抽象 1. js中的 ...

  7. 在浏览器中输入www.taobao.com后执行的全部过程

    >>>点击网址后,应用层的DNS协议会将网址解析为IP地址: DNS查找过程: 1.        浏览器会检查缓存中有没有这个域名对应的解析过的IP地址,如果缓存中有,这个解析过程 ...

  8. WebService 规范

    详见:https://blog.csdn.net/u011165335/article/details/51345224 JAVA 中共有三种WebService 规范,分别是JAX-WS(JAX-R ...

  9. lumen中安装及使用redis作为cache

      1.安装redis模块在compose.json的require中添加 "predis/predis": "*","illuminate/redi ...

  10. code first从入门到伪精通

    新入职一家公司,虽然之前也用ef,但是方式不一样,之前用的db,现在用代码先行的code,基于现有公司基本项目框架都是用的code,所以一步登顶,从最实战的角度去操作code,心颤的很,废话不多说,开 ...