字符串哈希

HASH

对于一个字符串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常数,双哈希来做。

//hash一般用来解决字符串判重/字符串匹配问题
//遇见不定长问题可通过二分+hash降低复杂度
//遇见定长字符串问题可通过尺取+hash来降低复杂度
//二维hash的时候尺取方法就是把之前不需要的都变为0再加上当前行,将匹配字符串整体下移,来验证hash值是否相等
//---------------------------------单Hash-----------------------
#include
typedef unsigned long long ull;
const int maxn=1e5+5;
ull hash_[maxn],xp[maxn];
void init()
{
    xp[0]=1;
    for(int i=1;i<maxn;i++)
        xp[i]=xp[i-1]*13331;//这里13331玄学数字,大概可以随意换
    return ;
}
void make_hash(char str[])//处理出str的hash值
{
    int len=strlen(str);
    hash_[len]=0;
    for(int i=len-1;i>=0;i--)
    {
        hash_[i]=hash_[i+1]*13331+str[i]-'A'+1;
    }
    return ;
}
ull Get_hash(int i,int L)//得到起点为i,长度为L的子串的hash值
{
    return hash_[i]-hash_[i+L]*xp[L];
}
//---------------------------------双Hash-----------------------
ll hash_[2][maxn],xp[2][maxn];
const int Mod1 = 1000000007;
const int Mod2 = 19260817;
void init()
{
    xp[0][0]=1;
    for(int i=1;i<maxn;i++)
        xp[0][i]=xp[0][i-1]*13331%Mod1;
    xp[1][0]=1;
    for(int i=1;i<maxn;i++)
        xp[1][i]=xp[1][i-1]*1331%Mod2;
    return ;
}
void make_hash(char str[])
{
    int len=strlen(str);
    hash_[0][len]=0;
    hash_[1][len]=0;
    for(int i=len-1;i>=0;i--)
    {
        hash_[0][i]=(hash_[0][i+1]*13331%Mod1+str[i]-'A'+1)%Mod1;
        hash_[1][i]=(hash_[1][i+1]*1331%Mod2+str[i]-'A'+1)%Mod2;
    }
    return ;
}
pll Get_hash(int i,int L)//得到起点为i,长度为L的子串的hash值
{
    return pll((hash_[0][i]-hash_[0][i+L]*xp[0][L]%Mod1+Mod1)%Mod1,(hash_[1][i]-hash_[1][i+L]*xp[1][L]%Mod2+Mod2)%Mod2);
}
//---------------------------------多Hash-----------------------
//T是Hash次数
//hash_interval [a,b)
template <int T>
struct StringHash
{
  std::vector<std::vector<int>> ha, pw;
  std::vector<int> M;

  explicit StringHash(const std::string& s)
      : StringHash(std::vector<int>(s.begin(), s.end())) {}

  explicit StringHash(const std::vector<int>& vec)
  {
    pw = ha =
        std::vector<std::vector<int>>(T, std::vector<int>(vec.size() + 1));
    std::vector<int> C;
    for (int i = 0; i < T; i++)
    {
      pw[i][0] = 1;
      C.push_back(rand_int());
      M.push_back(rand_int());
    }
    for (int z = 0; z < T; z++)
    {
      for (size_t i = 0; i < vec.size(); ++i)
      {
        ha[z][i + 1] = (1LL * ha[z][i] * C[z] + vec[i]) % M[z],
                  pw[z][i + 1] = 1LL * pw[z][i] * C[z] % M[z];
      }
    }
  }

  // hash value of interval [a, b)
  std::vector<int> hash_interval(int a, int b)
  {
    std::vector<int> ret(T);
    for (int z = 0; z < T; z++)
    {
      ret[z] = (ha[z][b] - 1LL * ha[z][a] * pw[z][b - a] % M[z] + M[z]) % M[z];
    }
    return ret;
  }

  static int rand_int() 
  {
    static std::mt19937 gen((std::random_device())());
    static std::uniform_int_distribution<int> uid(1e8, 1e9);
    return uid(gen);
  }
};

你可能感兴趣的:(模板_总结,HASH)