[Ybtoj High-efficiency Advanced 2.2] [hash] Word recitation

[Ybtoj High-efficiency Advanced 2.2] [hash] Word recitation

topic

Insert picture description here
Insert picture description here


Problem-solving ideas

Find the hash value of all words
Sort by hash value
Find the position of the word in the article in the word to be memorized
Enumerate the left boundary
because the left boundary is only moved one to the right, record the words contained in the current paragraph, and subtract the current left boundary That word is the beginning of the new paragraph. The
right boundary is continuously removed from the back. Non-remembered
words are included, just move the left boundary


Code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#define ull unsigned long long
using namespace std;
const ull p = 131;
struct lzf {
    
    
    int w;
    ull z;
} h[1020];
string x;
ull y;
int n, m, r, ans, dcs, ans1, a[1020000], v[1020];
bool cmp(lzf t, lzf f) {
    
     return t.z < f.z; }  //按哈希值培训
int find(ull y) {
    
    
    int l = 1, r = n;
    while (l <= r) {
    
    
        int mid = (l + r) / 2;
        if (h[mid].z < y)
            l = mid + 1;
        else if (h[mid].z > y)
            r = mid - 1;
        else
            return h[mid].w;
    }
    return -1;
}  //二分找位置
ull hash(string s) {
    
    
    ull ans = 0;
    int l = s.size();
    for (int i = 0; i < l; i++) ans = ans * p + (s[i] - '0');
    return ans;
}  //求哈希值
int main() {
    
    
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
    
    
        cin >> x;
        h[i].w = i;
        h[i].z = hash(x);
    }
    sort(h + 1, h + n + 1, cmp);
    scanf("%d", &m);
    for (int i = 1; i <= m; i++) {
    
    
        cin >> x;
        y = hash(x);
        int w = find(y);
        if (w > 0) {
    
    
            if (!v[w])
                ans++;  //能在文章里找到需背单词的个数
            v[w] = 1;
        }
        a[i] = w;
    }
    memset(v, 0, sizeof(v));
    r = 1, ans1 = 2147483647; //r是右边界,ans1是需背文章的长度
    for (int l = 1; l <= m; l++) {
    
    
        while (dcs < ans && r <= m) {
    
    
            if (a[r] >= 0) {
    
    
                if (!v[a[r]])
                    dcs++;
                v[a[r]]++;
            }  //
            r++;
        }  //更新当前段包含需背的单词
        if (dcs == ans)
            ans1 = min(ans1, r - l);  //包含所有能背的需背单词
        if (a[l] >= 0) {
    
    
            v[a[l]]--;
            if (!v[a[l]])
                dcs--;  //dcs是当前段包含需背的单词
        }
    }
    printf("%d\n%d", ans, ans1);
    return 0;
}

Guess you like

Origin blog.csdn.net/qq_45621109/article/details/114982371