[算法]hash算法

栈hash(可删除):

const int maxn = 5e6 + 5;
char a[maxn], b[maxn], sta[maxn];
unsigned int hsta[maxn], jian[maxn] = {1};
int main()
{
    for (int i = 1; i < maxn; ++i) jian[i] = jian[i - 1] * 31;
    while (~scanf("%s %s", b, a)){
        int la = strlen(a), lb = strlen(b), sp = 0;
        unsigned int hans = 0;
        for (int i = 0; i < lb; ++i) hans = hans * 31 + b[i];
        for(int i = 0; i < la; ++i){
            sta[++sp] = a[i];
            hsta[sp] = hsta[sp - 1] * 31 + sta[sp];
            if (sp > lb) hsta[sp] -= jian[lb] * sta[sp - lb];
            if (hsta[sp] == hans) sp -= lb;
        }
        sta[++sp] = '\0';
        puts(sta + 1);
    }
    return 0;
}

一维:

int main()
{
    scanf("%s%*c", m + 1);
    gets(s + 1);
    int i, lm = strlen(m + 1) + 2, ls = strlen(s + 1) + 2;
    m[0] = m[lm - 1] = s[0] = s[ls - 1] = ' ';
    for (int i = 1; i < lm - 1; ++i) if (isupper(m[i])) m[i] = tolower(m[i]);
    for (int i = 1; i < ls - 1; ++i) if (isupper(s[i])) s[i] = tolower(s[i]);
    ull hm = 0, hs = 0, sum = 1;
    for (i = 0; i < lm; ++i) sum *= h;
    for (i = 0; i < lm; ++i) hm = hm * h + m[i];
    for (i = 0; i < lm; ++i) hs = hs * h + s[i];
    int p;
    for (i = 0; i + lm <= ls; ++i){
        if (hs == hm){
            p = i;
            break;
        }
        hs = hs * h - s[i] * sum + s[i + lm];
    }
    if (i > ls - lm) return 0 & puts("-1");
    int ans = 0;
    for (; i + lm <= ls; ++i){
        if (hs == hm) ++ans;
        hs = hs * h - s[i] * sum + s[i + lm];
    }
    printf("%d %d\n", ans, p);
    return 0;
}

https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1347
一道二愣子题愣是被我写成了滚动hash,我也是醉了,脑子不好使了吧,那这个hash就当模板吧
我们把对串旋转几次就可以发现一个对串不管旋转多少次都是对串。

unsigned int a, b, t = 1;
int main()
{
    string s;
    while (cin >> s){
        int ls = s.size();
        if (ls & 1){
            puts("NO");
            continue;
        }
        ls /= 2;
        for (int i = 0; i < ls; ++i) t *= mod;
        for (int i = 0; i < ls; ++i) a = a * mod + s[i];
        for (int i = ls; i < 2 * ls; ++i) b = b * mod + s[i];
        s += s;
        bool yes = 0;
        for (int i = 0; i < ls; ++i){
            if (a == b){
                yes = 1;
                puts("YES");
                break;
            }
            a += - t * s[i] + s[i + ls];
            b += - t * s[i + ls] + s[i + 2 * ls];
        }
        if (!yes) puts("NO");
    }
    return 0;
}

二维:BZOJ – 矩阵模板
https://cn.vjudge.net/contest/243932#problem/O
原来unsigned int和unsigned long long都会自然溢出,但是unsigned long long会TLE,再也不用这个了。
另外,原来还可以直接对结果hash存表然后O(1)查找,太厉害了啊。
woc刚才把p = 99999971改成1000007直接快了一秒,还是恐怖啊,应该就是越接近10的倍数处理的越快。
各种优化之后从1800ms降到了500ms。

#include<bits/stdc++.h>
#define maxn 1005
using namespace std;
typedef unsigned int ui;
const ui b1 = 31, b2 = 107, p = 1000007;
char g[maxn][maxn];
ui res[maxn][maxn], p1 = 1, p2 = 1;
int n, m, a, b, q;
bool hashp[p];
void init_hash()
{
    for (int i = 0; i < n; ++i){
        ui e = 0;
        for (int j = 0; j < b; ++j)
            e = e * b1 + g[i][j];
        for (int j = 0; j + b < m; ++j){
            res[i][j] = e;
            e = e * b1 - p1 * g[i][j] + g[i][j + b];
        }
        res[i][m - b] = e;
    }
    for (int j = 0; j + b <= m; ++j){
        ui e = 0;
        for (int i = 0; i < a; ++i)
            e = e * b2 + res[i][j];
        for (int i = 0; i + a < n; ++i){
            hashp[e % p] = 1;
            e = e * b2 - p2 * res[i][j] + res[i + a][j];
        }
        hashp[e % p] = 1;
    }
}
ui c_hash()
{
    ui e2 = 0, e1 = 0;
    for (int i = 0; i < a; ++i, e1 = 0){
        for (int j = 0; j < b; ++j){
            e1 = e1 * b1 + g[i][j];
        }
        e2 = e2 * b2 + e1;
    }
    return e2;
}
int main()
{
    scanf("%d %d %d %d", &n, &m, &a, &b);
    for (int i = 0; i < b; ++i) p1 *= b1, p2 *= b2;
    for (int i = 0; i < n; ++i) scanf("%s", g[i]);
    init_hash();
    scanf("%d", &q);
    while (q--){
        for (int i = 0; i < a; ++i) scanf("%s", g[i]);
        if (hashp[c_hash() % p]) puts("1");
        else puts("0");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值