zoukankan      html  css  js  c++  java
  • LOJ2823 三个朋友 ——查询字串的哈希值

    概念

    查询字串的hash值

    我们所说的哈希通常都是进制哈希,因为它具有一些很方便的性质,例如,具有和前缀和类似的性质。

    假设一个字符串的前缀哈希值记为 $h[i]$,进制为 $base$,那么显然 $h[i] = h[i-1] imes base + s[i]$.

    记 $p[i]$ 为 $base$ 的 $i$ 次方,那么我们可以 $O(1)$ 得到一个字串的哈希值。

    typedef unsigned long long ull;
    ull get_hash(int l, int r) {
        return h[r] - h[l - 1] * p[r - l + 1];
    }

    其中,乘以 $p[r-l+1]$ 相当于左移了 $r-l+1$ 位。

    同样,我们可以 $O(1)$ 得到字串中删除一个字符后的hash值。

    ull get_s(int l, int r, int x) {
        return get_hash(l, x - 1) * p[r - x] + get_hash(x + 1, r);
    }

    例题

    题意:给定一个字符串 $S$,先将字符串 $S$ 复制一次,得到字符串 $T$,然后在 $T$ 中插入一个字符,得到字符串 $U$。现给出字符串 $U$,要求重新构造出 $S$。

    分析:

    枚举每一个位置,剩下的应是两个相同的字符串,根据hash值判断一下。

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    typedef unsigned long long ull;
    const ull base = 233;
    const int maxn = 2000000+10;
    ull h[maxn], p[maxn];
    char s[maxn];
    int len;
    
    void init()
    {
        ll ans = 0;
        for(int i=0;i<len;i++)
        {
            ans = (ans*base) + (ull)s[i];
            h[i] = ans;
        }
        p[0] = 1;
        for(int i=1;i<=len;i++)
        {
            p[i] = p[i-1]*base;
        }
    }
    
    inline ll gethash(int l,int r)
    {
        return h[r] - h[l-1]*p[r-l+1];
    }
    
    inline ll del(int l,int r,int x)
    {
        if(x<l||x>r)
            return gethash(l,r);
        return gethash(l,x-1)*p[r-x]+gethash(x+1,r);
    }
    
    inline int check(int x) //检查去掉第x位时是否合法
    {
        if(x<=len/2&&del(0,len-1,x)==del(0,len>>1,x)*p[len>>1]+del(0,len>>1,x))
            return 1;
        else if(x>len/2&&del(0,len-1,x)==del(0,(len>>1)-1,x)*p[len>>1]+del(0,(len>>1)-1,x))
            return 1;
        else
            return 0;
    }
    
    int main()
    {
        scanf("%d",&len);
        scanf("%s",s);
        init();
        int cnt = 0;
        int ii = -1;
        ll num;
        for(int i=0;i<len;i++)
        {
            if(check(i))
            {
                cnt++;
                if(ii==-1)
                {
                    ii=i;
                    num = del(0,len-1,i);
                }
                else
                {
                    if(del(0,len-1,ii)==del(0,len-1,i))  //可能是相同的串
                        cnt--;
                }
            }
            if(cnt==2)
            {
                printf("NOT UNIQUE
    ");
                return 0;
            }
        }
        if(cnt==1)
        {
            int m = 0;
            for(int j=0;j<len;j++)   //输出结果
            {
                if(j==ii)
                    continue;
                printf("%c",s[j]);
                m++;
                if(m==(len-1)/2)
                    break;
            }
            printf("
    ");
        }
        if(cnt==0)
        {
            printf("NOT POSSIBLE
    ");
        }
        return 0;
    }

    参考链接:https://loj.ac/submission/576434

  • 相关阅读:
    redis主从架构
    redis持久化
    git 首次push失败
    Java8 CompletableFuture
    Mac Item2自动远程连接服务器
    Java8 日期和时间类
    【LeetCode】31. 下一个排列
    【LeetCode】30. 串联所有单词的子串
    【LeetCode】29. 两数相除
    【LeetCode】28. 实现 strStr()
  • 原文地址:https://www.cnblogs.com/lfri/p/11375342.html
Copyright © 2011-2022 走看看