牛客寒假集训营第四场B字符串哈希+二分

12 篇文章 0 订阅
3 篇文章 0 订阅

题目

武辰延的字符串

赛时没想到hash O ( 1 ) O(1) O(1)判断

枚举S1,二分S2长度,利用Hash判断两字符串相等。

代码

AC代码:

/*
 * @Author: hesorchen
 * @Date: 2020-11-26 09:12:46
 * @LastEditTime: 2021-02-21 16:19:05
 * @Description: 栽种绝处的花
 */
#include <bits/stdc++.h>
using namespace std;

const unsigned long long base = 13331;
unsigned long long pre_pow[100010];

string a, b;
int len1, len2;
void pre()
{
    len1 = a.size(), len2 = b.size();
    a = ' ' + a;
    b = ' ' + b;
    pre_pow[0] = 1;
    for (int i = 1; i <= 100000; i++)
        pre_pow[i] = pre_pow[i - 1] * base;
}
unsigned long long Hasha[100010], Hashb[100010], ans;

void gethash()
{

    for (int i = 1; i <= len1; i++)
        Hasha[i] = Hasha[i - 1] * base + a[i];
    for (int i = 1; i <= len2; i++)
        Hashb[i] = Hashb[i - 1] * base + b[i];
}
bool check(int s1, int s2)
{
    unsigned long long res1 = Hasha[s1] * pre_pow[s2];
    unsigned long long res2 = Hasha[s2];
    unsigned long long res3 = res1 + res2;
    if (res3 == Hashb[s1 + s2])
        return true;
    return false;
}
void getans()
{
    for (int i = 1; i <= len1; i++)
    {
        if (i < len2 && Hasha[i] == Hashb[i] && a[1] == b[i + 1])
        {
            int l = 1, r = len2 - i, res = 0;
            while (l <= r)
            {
                int mid = l + r >> 1;
                if (check(i, mid))
                {
                    l = mid + 1;
                    res = mid;
                }
                else
                    r = mid - 1;
            }
            ans += res;
        }
    }
}
int main()
{
    cin >> a >> b;
    pre();
    gethash();
    getans();
    cout << ans << endl;

    return 0;
}

双哈希代码(练习):

/*
 * @Author: hesorchen
 * @Date: 2020-11-26 09:12:46
 * @LastEditTime: 2021-02-21 16:26:34
 * @Description: 栽种绝处的花
 */
#include <bits/stdc++.h>
using namespace std;

const unsigned long long base = 13331, base2 = 1331;
unsigned long long pre_pow[100010];
unsigned long long pre_pow2[100010];
unsigned long long Hasha[100010], Hashb[100010], ans;
unsigned long long Hasha2[100010], Hashb2[100010];

string a, b;
int len1, len2;
void pre()
{
    len1 = a.size(), len2 = b.size();
    a = ' ' + a;
    b = ' ' + b;
    pre_pow[0] = 1;
    for (int i = 1; i <= 100000; i++)
        pre_pow[i] = pre_pow[i - 1] * base;
    pre_pow2[0] = 1;
    for (int i = 1; i <= 100000; i++)
        pre_pow2[i] = pre_pow2[i - 1] * base2;
}

void gethash()
{

    for (int i = 1; i <= len1; i++)
        Hasha[i] = Hasha[i - 1] * base + a[i];
    for (int i = 1; i <= len2; i++)
        Hashb[i] = Hashb[i - 1] * base + b[i];

    for (int i = 1; i <= len1; i++)
        Hasha2[i] = Hasha2[i - 1] * base2 + a[i];
    for (int i = 1; i <= len2; i++)
        Hashb2[i] = Hashb2[i - 1] * base2 + b[i];
}
bool check(int s1, int s2)
{
    int flag1 = 0, flag2 = 0;
    unsigned long long res1 = Hasha[s1] * pre_pow[s2];
    unsigned long long res2 = Hasha[s2];
    unsigned long long res3 = res1 + res2;
    if (res3 == Hashb[s1 + s2])
        flag1 = 1;
    res1 = Hasha2[s1] * pre_pow2[s2];
    res2 = Hasha2[s2];
    res3 = res1 + res2;
    if (res3 == Hashb2[s1 + s2])
        flag2 = 1;
    return (flag1 && flag2);
}
void getans()
{
    for (int i = 1; i <= len1; i++)
    {
        if (i < len2 && Hasha[i] == Hashb[i] && Hasha2[i] == Hashb2[i] && a[1] == b[i + 1])
        {
            int l = 1, r = len2 - i, res = 0;
            while (l <= r)
            {
                int mid = l + r >> 1;
                if (check(i, mid))
                {
                    l = mid + 1;
                    res = mid;
                }
                else
                    r = mid - 1;
            }
            ans += res;
        }
    }
}
int main()
{
    cin >> a >> b;
    pre();
    gethash();
    getans();
    cout << ans << endl;

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hesorchen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值