zhuan [讲解] OI 字符串 常用哈希方法(by sxy sxy)
下面这个方法来自 算法竞赛入门经典-训练指南
方法
对于一个字符串s,令h[i] = h[i+1]*x + s[i] ,其中x是你自选的一个常数。令xp[i] = xp[i-1]*x
这样之后定义s的起点为下标i,长度为len的子串的哈希值为 h[i] - h[i+len]*xp[len] 。这个值与子串的位置,子串的内容,还有你自选的常数都有关系。哈希值使用unsigned long long(如果不是oi,可以使用int128的话当然更好) 不同子串的哈希值一定不会相同吗?不一定,但是相同的概率非常非常小。如果觉得不够保险可以分别选定两次x常数,双哈希来做。
应用
- 找最长公共子串 http://syzoj.com/problem/186
dp超时,后缀数组RE了?(orz Fmuckss神犇),后缀自动机不会写?来写易于理解速度也相当不错的哈希吧。
这里有两个字符串,分别给两个字符串做哈希,然后二分直接二分答案len,计算两个字符串每个起点开始长度为len的子串的哈希(O(n)的)。然后给第两个字符串的长度为len的子串的哈希值排序。枚举第一个字符串的哈希,在第二个字符串的哈希里面用lower_bound找(这也是之前给它排序的原因,排好序就可以lower_bound),找到了就说明存在这样长度的最长公共子串。于是AC代码如下(最后总共用时约1800ms,约是后缀自动机的9倍):
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <list>
#include <queue>
#include <algorithm>
using namespace std;
typedef unsigned long long ULL;
#define MAXN 200003
ULL xp[MAXN];
ULL hasha[MAXN];
ULL hashb[MAXN];
ULL ha[MAXN];
ULL hb[MAXN];char A[MAXN], B[MAXN];
int x = 233;
int la, lb;
int mlen;
int minlen;
bool check(int len)
{for(int i = 0; i < la-len+1; i++)hasha[i] = ha[i] - ha[i+len]*xp[len];for(int i = 0; i < lb-len+1; i++)hashb[i] = hb[i] - hb[i+len]*xp[len];sort(hashb, hashb+lb-len+1);for(int i = 0; i < la-len+1; i++){ULL h = hasha[i];int p = lower_bound(hashb, hashb+lb-len+1, h)-hashb;if(p < lb-len+1 && h == hashb[p])return true;}return false;
}int main()
{scanf("%s %s", A, B);la = strlen(A);lb = strlen(B);mlen = max(la, lb);minlen = min(la, lb);for(int i = la-1; i >= 0; i--)ha[i] = ha[i+1]*x + A[i];for(int i = lb-1; i >= 0; i--)hb[i] = hb[i+1]*x + B[i];xp[0] = 1;for(int i = 1; i <= mlen; i++)xp[i] = xp[i-1]*x;int l = 0, r = minlen;int ans;while(l <= r){int m = (l+r)>>1;if(check(m)){ans = m;l = m+1;}elser = m-1;}printf("%d\n", ans);return 0;
}
- 出现次数超过m次的最长的子串 (uva 12206 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=505&problem=3358&mosmsg=Submission+received+with+ID+18140839
最长这个条件优先,因此还是二分长度。每次检查是否存在这样一个出现次数超过m次的子串即可。将哈希值排序可以把哈希值相同的子串的哈希值排在一起,这样之后就能O(n)时间判断出超过次数是否超过m次。代码
哈希用途广泛,是个非常好的东西。
/*
submition url:
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=505&page=show_problem&problem=3358
*/
#include <cstdio>
#include <cstdlib>
#include <cstdarg>
#include <cstring>
#include <list>
#include <queue>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
int m;
char str[40002];
typedef unsigned long long ULL;
ULL h[40002];
ULL hhash[40002];
ULL xp[40002];
int rrank[40002];
int x = 123;
int slen;
int pos;
bool cmp(int a, int b)
{return hhash[a] < hhash[b] || (hhash[a] == hhash[b] && a < b);
}
void calc()
{slen = strlen(str);h[slen] = 0;for(int i = slen-1; i >= 0; i--)h[i] = h[i+1]*x + str[i];xp[0] = 1;for(int i = 1; i <= slen; i++)xp[i] = xp[i-1]*x;
}
bool check(int len)
{for(int i = 0; i < slen-len+1; i++){rrank[i] = i;hhash[i] = h[i] - h[i+len]*xp[len];}sort(rrank, rrank+slen-len+1, cmp);int times = 0;pos = -1;for(int i = 0; i < slen-len+1; i++){if(i == 0 || hhash[rrank[i]] != hhash[rrank[i-1]])times = 0;if(++times >= m)pos = max(pos, rrank[i]);}return pos >= 0;
}
void solve()
{if(!check(1)){puts("none");return;}int l = 0, r = slen;int ans = 0;while(l <= r){int m = (l+r)>>1;if(check(m)){ans = m;l = m+1;}elser = m-1;}check(ans);if(ans)printf("%d %d\n", ans, pos);elseputs("none");
}
int main()
{while(true){scanf("%d", &m);if(!m)break;scanf("%s", str);calc();solve();}return 0;
}
from:http://sxysxy.org/blogs/44
zhuan [讲解] OI 字符串 常用哈希方法(by sxy sxy)相关推荐
- JS字符串常用属性、方法
文章目录 属性 length constructor prototype 方法 charAt() charCodeAt() concat() indexOf() lastIndexOF() slice ...
- 一次性汇总了 30+ 字符串常用处理方法
今天这篇推文我们就汇总下Python中常用的字符串处理小技巧,字符串在Python数据处理中是非常常见且极易忽略的常用数据类型,且Python本身也提供大量运算符.函数和方法来处理字符串.话不多说,接 ...
- 基础数据结构(二):字典树、并查集、堆、哈希表、字符串的哈希方式、STL的常见容器及其接口
文章目录 一.字典树Trie 1 原理 2 Trie字符串统计 3 [LeetCode 208. 实现 Trie (前缀树)](https://leetcode-cn.com/problems/imp ...
- ML之相似度计算:图像数据、字符串数据等计算相似度常用的十种方法简介、代码实现
ML之相似度计算:图像数据.字符串数据等计算相似度常用的十种方法简介.代码实现 目录 相似度 1.余弦相似性-夹角余弦(Cosine_Distance)距离 2.代码实现-余弦距离.余弦相似度 2.皮 ...
- Java中字符串的常用属性与方法
•字符串常用的属性 string.length()---->返回字符串的长度,int类型. •字符串常用的方法 String.contains(";")------>判 ...
- python字符串三种常用的方法或函数_python中字符串常用的函数
s ="hello world" s[2] >>> "l" 索引 s.index("l") >>> 2 ...
- ML:图像数据、字符串数据等计算相似度常用的十种方法(余弦相似性、皮尔逊、闵可夫斯基距离/曼哈顿距离/欧氏距离/切比雪夫距离、马氏距离、汉明距离、编辑距离、杰卡德相似系数、相对熵/KL散度、Helli
ML:图像数据.字符串数据等计算相似度常用的十种方法(余弦相似性.皮尔逊.闵可夫斯基距离/曼哈顿距离/欧氏距离/切比雪夫距离.马氏距离.汉明距离.编辑距离.杰卡德相似系数.相对熵/KL散度.Helli ...
- C++字符串常用输入方法
字符串常用输入方法总结 前言: 个人是从两个角度去比较思考总结的 (1)能否输入空格 (2)输入支持的是 ①单个字符 ②还是char[]字符数组 ③还是string类字符串 1.scanf(" ...
- 字符串的常用内置方法
字符串的常用内置方法 capitalize() 将字符串的第一个字符转换为大写. lower() 转换字符串中所有大写字符为小写. upper() 转换字符串中的小写字母为大写. swapcase() ...
- python数据处理常用函数_Python中常用操作字符串的函数与方法总结
Python中常用操作字符串的函数与方法总结 这篇文章主要介绍了Python中常用操作字符串的函数与方法总结,包括字符串的格式化输出与拼接等基础知识,需要的朋友可以参考下 例如这样一个字符串 Pyth ...
最新文章
- JAVA基础——编程练习(一)
- 论排列组合,持续更新
- 黑莓作为猫带笔记本上网
- 编码过程中的问题总结
- win7系统控制面板下的打开或关闭windows功能需要打开哪些功能
- 手把手教你C语言静态库的开发
- 索引中丢失 IN 或 OUT 参数
- 揭秘视频千倍压缩背后的技术原理之预测技术
- LeetCode 929. 独特的电子邮件地址
- matlab破损皮革定位,matlab-code-of-TDOAFDOa 干扰源定位代码,应该在 的求解过程中有帮助。 276万源代码下载- www.pudn.com...
- oracle em搭建,【oracle】手动安装EM
- BZOJ-4008: [HNOI2015]亚瑟王 (概率期望DP)
- typeorm实战之findOne()方法
- 方维直播源码无BUG修复最新版!
- 微信小程序云开发之云函数与本地数据库获取数据
- 广告行业计费模式专业术语
- mysql 联合主键 加锁_MySQL 加锁处理分析
- 从Mpx资源构建优化看splitChunks代码分割
- Dubbo3.0系列(6)- Dubbo3.0支持的RPC协议
- 读书笔记-《wxPython in Action》一
热门文章
- Photoshop图片秒变素描方法,非常简单
- Java面向对象编程(五)特殊类
- 互联网和人工智能之间,主要是什么关系?
- Linux查看mpp数据库地址,Linux环境搭建DM8 MPP双节点集群
- 展现量、点击量、点击率;访客数、访问次数、浏览量的区别与作用
- 上dnf一直连接服务器中,Win7系统下玩dnf提示正在连接服务器如何解决
- 全球计算机科学和电子,科学网—[转载]【喜报】祝贺IEEE TCSS入选全球计算机与电子领域Top 1000期刊 - 王飞跃的博文...
- 数据、程序、文件区别
- 《正见——佛陀的证悟》读后感
- C语言实现安全性极高的游戏存档并读档