2021CCPC女生专场 F. 地图压缩 子串hash+二维KMP

https://codeforces.com/gym/103389/problem/F
做这个题之前要做一下 p o j 2185 poj2185 poj2185,这两个题很像,但是这个题有多次询问,所以如果每次都去计算一次所给矩形的最小循环节,如果对字符串进行逐个字符的比较,那么复杂度是 O ( n 2 q ) O(n^2q) O(n2q),不行,所以想到哈希,使用子串哈希的方法,使用字符串的哈希值来进行 k m p kmp kmp,这样复杂度就降到了 O ( n 2 + n q ) O(n^2+nq) O(n2+nq)

  • 进制 h a s h hash hash,如果设原来的字符串为 s s s,如果字符串都是小写字母,那么有 h a s h [ i ] = h a s h [ i − 1 ] × b a s e + s [ i ] − ′ a ′ hash[i]=hash[i-1]\times base + s[i]-'a' hash[i]=hash[i1]×base+s[i]a p [ i ] = p [ i − 1 ] × b a s e , ( p [ 0 ] = 1 ) p[i]=p[i-1]\times base,(p[0]=1) p[i]=p[i1]×base,(p[0]=1)其中 b a s e base base可取 13131 13131 13131,这里减不减 ′ a ′ 'a' a应该都行,如果想得到一个子串的 h a s h hash hash值,那么如果子串是 [ l , r ] [l,r] [l,r],那么有子串哈希值为 h a s h [ r ] − h a s h [ l − 1 ] × p [ r − l + 1 ] hash[r]-hash[l-1]\times p[r-l+1] hash[r]hash[l1]×p[rl+1]
#include <bits/stdc++.h>

using namespace std;

typedef unsigned long long ull;
ull base = 13131;
int main(){
    
    
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n, q;
    cin >> n >> q;
    vector<vector<char> > mp(n + 1, vector<char> (n + 1));
    vector<vector<ull> > row(n + 1, vector<ull>(n + 1)), col(n + 1, vector<ull>(n + 1));
    vector<ull> p(n + 1);
    p[0] = 1;
    for(int i=1;i<=n;i++){
    
    
        p[i] = p[i - 1] * base;
        for(int j=1;j<=n;j++){
    
    
            cin >> mp[i][j];
            row[i][j] = row[i][j - 1] * base + mp[i][j] - 'a';
            col[i][j] = col[i - 1][j] * base + mp[i][j] - 'a';
        }
    }
    while(q--){
    
    
        int x1, x2, y1, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        int res = x2 - x1 + 1;
        vector<int> Next(res + 1);
        vector<ull> a(res + 1);
        for(int i=x1;i<=x2;i++){
    
    
            function<ull(int, int)> Get_Row = [&](int l, int r){
    
    
                return row[i][r] - row[i][l - 1] * p[r - l + 1];
            };
            a[i - x1] = Get_Row(y1, y2);
        }
        for(int i=1;i<res;i++){
    
    
            int j = Next[i];
            while(j && a[i] != a[j]) j = Next[j];
            Next[i + 1] = (a[i] == a[j] ? j + 1 : 0);
        }
        int x = res - Next[res];
        res = y2 - y1 + 1;
        Next.resize(res + 1);
        Next[1] = 0;
        a.resize(res + 1);
        for(int i=y1;i<=y2;i++){
    
    
            function<ull(int, int)> Get_Col = [&](int l, int r){
    
    
                return col[r][i] - col[l - 1][i] * p[r - l + 1];
            };
            a[i - y1] = Get_Col(x1, x2);
        }
        for(int i=1;i<res;i++){
    
    
            int j = Next[i];
            while(j && a[i] != a[j]) j = Next[j];
            Next[i + 1] = (a[i] == a[j] ? j + 1 : 0);
        }
        int y = res - Next[res];
        cout << x * y << '\n';
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/roadtohacker/article/details/121304173
今日推荐