2021牛客寒假算法基础集训营4 字符串哈希成数字 二分枚举可行长度

题目

在这里插入图片描述

题解思路

在这里插入图片描述
因为字符串hash是从第一位往第N位乘 进制
所以第一位会被乘N次。
当我们要去 i 到 j 的hash值的时候
让hash[j]减去hash[i-1]*(j-i+1)*进制
相当与吧hash[i-1]加了(j-i+1)个 0 。这样一减就是 i 到 j 的hash值的实值了。
有点难理解

和普通数字的进制有点相反,多模拟几遍。

枚举每个相同的前缀,
这样就可以直接二分可以延展的最大的长度了。
根据可行性二分枚举。
最大长度减了一点还是可以拼接成他的子串。

属实巧妙

AC代码
#include <bits/stdc++.h>
//#include <unordered_map>
//priority_queue
#define PII pair<int,int>
#define ll long long

using namespace std;

const  int  INF =  0x3f3f3f3f;
const  int  mod = 1e9 + 7 ;
const  int N = 100010 ;
const  int mi = 266 ; 

long long a[N] ; 
long long b[N] ; 

void calc( string sk , long long p[] )
{
    for (int i = 0 ; i < sk.size() ; i++ )
    {
        if ( i == 0 )
        {
            p[i] = (sk[i] - 'a' )%mod ;
        }else
            p[i] = ( p[i-1]*mi + sk[i] - 'a')%mod ; 
    }
}
long long qsm(long long di , long long mi )
{
    long long res = 1 ;
    while (mi)
    {
        if (mi&1)
            res = res * di %mod ;
        mi >>= 1 ;
        di = di*di%mod ; 
    }
    return res ; 
}
long long calchash(long long a[] , int l , int r )
{
    if ( l == 0 )
        return a[r] ; 
    long long tmp ; 
    tmp = ( ( a[r] - a[l-1]*qsm(mi,r-l+1)%mod )%mod + mod )%mod ;
    return tmp ;
}
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    string s , t ;
    cin >> s >> t ;
    calc(s,a);
    calc(t,b);
    long long ans = 0 ; 
    int sl = s.size();
    int tl = t.size();
    for (int i = 0 ; i < sl ; i++ )
    {
        if ( s[i] != t[i] ) 
            break ;
        int l = 0 , r = sl - 1 ; 
        while ( l <= r )
        {
            int mid = (l+r)/2 ; 
            long long sh = a[mid] ;
            long long th ; 
            if ( i + 1 + mid >= tl )
                th = -1 ; 
            else
                th = calchash(b,i+1,i+1+mid) ;
            if ( sh == th )
                l = mid + 1 ;
            else
                r = mid - 1 ; 
        }
        ans += l ;
    }
    cout << ans << "\n" ; 
    return 0 ;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值