YBTOJ 2.2Hash 和 Hash 表

A.字符串匹配

image
image

板子题 详细解释见哈希学习笔记

点击查看代码
#include <bits/stdc++.h>
using namespace std;

const int N = 1e9 + 7;
const int b = 37;
long long h[100721], prs = 0;

void hashe(string s) {
    long long len = s.length();
    long long ch = 1, sum = (long long)(s[0]) * b % N;
    for (long long i = 1; i < len; ++i) {
        ch = ch * b % N;
        sum = (sum + (ch * s[i] * b % N)) % N;
    }
    h[++prs] = sum;
}

int main() {
    long long n;
    scanf("%lld", &n);
    long long ans = n;
    for (long long i = 1; i <= n; ++i) {
        string s;
        cin >> s;
        hashe(s);
        for (int j = 1; j < prs; ++j) {
            if (h[j] == h[prs]) {
                ans--;
                break;
            }
        }
    }

    printf("%lld", ans);

    return 0;
}

B.回文子串

image
image

为什么我在马拉车
当然哈希也能做 我们把这个字符串弄一个反过来的版本
然后二分一个长度来 check 即可
代码是马拉车(

点击查看代码
#include <bits/stdc++.h>
using namespace std;

const int N = 2e6 + 0721;
int pdr[N];
int ans, mid, mr;

int main() {
    char s1[N];
    int cas = 0;
    while (scanf("%s", s1)) {
        if (s1[0] == 'E')
            break;
        memset(pdr, 0, sizeof(pdr));
        ans = mid = mr = 0;
        ++cas;
        string s;
        int len = strlen(s1);
        s += '~';
        s += '#';
        for (int i = 0; i < len; ++i) {
            s += s1[i];
            s += '#';
        }
        s += '$';

        len = (len << 1) + 1;
        for (int i = 1; i < len; ++i) {
            if (i <= mr)
                pdr[i] = min(pdr[(mid << 1) - i], mr - i);
            else
                pdr[i] = 1;
            while (s[i + pdr[i]] == s[i - pdr[i]]) pdr[i]++;
            if (pdr[i] + i - 1 > mr)
                mr = pdr[i] + i - 1, mid = i;
        }

        for (int i = 1; i < len; ++i) ans = max(ans, pdr[i] - 1);
        printf("Case %d: %d\n", cas, ans);
    }

    return 0;
}

C.对称正方形

image
image

主题思路和上题一样 二分正方形的最大边长
对于一个大对称正方形 小一圈同样也是对称正方形
主要是二维哈希判断
代码因为我写挂了并且调破防了所以就不贴了


D.单词背诵

image
image

非常经典的一道双指针 每次移动左指针就把上一个位置的单词出现次数--
如果那个单词出现次数变成了 \(0\) 就不断右移右指针 将扫到的单词出现次数++ 直到再次出现那个单词
至于如何判断相同单词 直接 \(STL\) 即可

点击查看代码
#include <bits/stdc++.h>
using namespace std;

map<string, int> word;
map<string, bool> flag;
int c[0x0d00], q[100721], f[100721];
int n, m, head, cnt, prs;

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        string s;
        cin >> s;
        flag[s] = 1;
        word[s] = ++head;
    }

    head = 0;
    scanf("%d", &m);
    for (int i = 1; i <= m; ++i) {
        string s;
        cin >> s;
        if (flag[s]) {
            cnt++;
            flag[s] = 0;
        }
        q[++head] = word[s];
    }

    if (cnt == 0) {
        printf("0\n0");
        return 0;
    }
    printf("%d\n", cnt);

    int l = 1, r = 0;
    while (r <= head) {
        while (1) {
            if (prs == cnt)
                break;
            r++;
            if (r > head)
                break;
            if (q[r] == 0)
                continue;
            if (c[q[r]] == 0) {
                c[q[r]]++;
                prs++;
                if (prs == cnt)
                    break;
            } else
                c[q[r]]++;
        }

        if (prs == cnt) {
            f[l] = r;
            c[q[l]]--;
            if (c[q[l]] == 0)
                prs--;
            l++;
        }
    }

    int ans = 0x7fffffff;
    for (int i = 1; i <= m; ++i) {
        if (f[i] != 0)
            ans = min(ans, f[i] - i + 1);
    }

    printf("%d", ans);

    return 0;
}
posted @ 2023-06-28 16:09  Steven24  阅读(41)  评论(0编辑  收藏  举报