字符串Hash

目录

字符串Hash

定义

性质

多项式取模Hash

自然溢出

双模Hash

板子

子串的基础定义

S[l,r]

PrefixS[i]

SuffixS[i]

获得子串Hash值的方法


字符串Hash

定义

Hash是种单射函数,可将万物单向映射成一个整数值。

字符串Hash通过把字符串S映射成一个整数值H(S)来快速比较(O(1))两个字符串是否相等。

性质

S=T→H(T)=H(S)

(必要性、非充分性)

多项式取模Hash

方法:把S看成某进制(base)下的数字串,并将得到的H(S)对一个尽量大(接近n²,n是Hash检验次数)的质数取模。

公式:H(S)=H(S[1,|S|-1])*BASE+S[|S|];

自然溢出

用ULL保存Hash,自然溢出(肯定会被卡掉)。

双模Hash

在不泄露模数的情况下,没有已知方法可以构造冲突。

const int mod1 = 1000000007;
const int mod2 = 1000000009;

板子

云剪贴板 - 洛谷

子串的基础定义

S[l,r]

表示字符串S从第l个到第r个字母顺次连接成的新字符串。

PrefixS[i]

字符串S长度为i的前缀(1~i);

SuffixS[i]

字符串S长度为i的后缀(n-i+1~n);

获得子串Hash值的方法

H(l,r) = H(r)-H(l-1)*pow(base,r-l+1)

例题:Seek the Name, Seek the Fame

The little cat is so famous, that many couples tramp over hill and dale to Byteland, and asked the little cat to give names to their newly-born babies. They seek the name, and at the same time seek the fame. In order to escape from such boring job, the innovative little cat works out an easy but fantastic algorithm:

Step1. Connect the father's name and the mother's name, to a new string S.
Step2. Find a proper prefix-suffix string of S (which is not only the prefix, but also the suffix of S).

Example: Father='ala', Mother='la', we have S = 'ala'+'la' = 'alala'. Potential prefix-suffix strings of S are {'a', 'ala', 'alala'}. Given the string S, could you help the little cat to write a program to calculate the length of possible prefix-suffix strings of S? (He might thank you by giving your baby a name:)

Input

The input contains a number of test cases. Each test case occupies a single line that contains the string S described above.

Restrictions: Only lowercase letters may appear in the input. 1 <= Length of S <= 400000.

Output

For each test case, output a single line with integer numbers in increasing order, denoting the possible length of the new baby's name.

Sample

InputcopyOutputcopy
ababcababababcabab
aaaaa
2 4 9 18
1 2 3 4 5

简析:先预处理hash和pow并写出get函数。

#ifndef _GLIBCXX_NO_ASSERT
#include <cassert>
#endif
#include <cctype>
#include <cerrno>
#include <cfloat>
#include <ciso646>
#include <climits>
#include <clocale>
#include <cmath>
#include <csetjmp>
#include <csignal>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
 
#if __cplusplus >= 201103L
#include <ccomplex>
#include <cfenv>
#include <cinttypes>
#include <cstdalign>
#include <cstdbool>
#include <cstdint>
#include <ctgmath>
#include <cuchar>
#include <cwchar>
#include <cwctype>
#endif
 
// C++
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <typeinfo>
#include <utility>
#include <valarray>
#include <vector>
 
#if __cplusplus >= 201103L
#include <array>
#include <atomic>
#include <chrono>
#include <codecvt>
#include <condition_variable>
#include <forward_list>
#include <future>
#include <initializer_list>
#include <mutex>
#include <random>
#include <ratio>
#include <regex>
#include <scoped_allocator>
#include <system_error>
#include <thread>
#include <tuple>
#include <typeindex>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#endif
 
#if __cplusplus >= 201402L
#include <shared_mutex>
#endif
 
#if __cplusplus >= 201703L
#include <charconv>
#include <filesystem>
#endif

using namespace std;
typedef unsigned long long ull;
ull n,p[400002]={1},h[400002]={0},b=131;
string s;
ull get(int l,int r)
{
	return h[r]-h[l-1]*p[r-l+1];
}
void solve()
{
	n=s.size();
	char str[400002];
	for(int i=1;i<=n;i++)
	{
		str[i]=s[i-1];
		p[i]=p[i-1]*b;
		h[i]=h[i-1]*b+str[i]-'0';
	}
	for(int i=1;i<=n;i++)
	{
		if(get(1,i)==get(n-i+1,n))
		{
			cout<<i;
			if(i<n)cout<<' ';
		}
	}
}
int main()
{
	while(cin>>s)
	{
		solve();
		cout<<'\n';
	}
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值