• CSAcademy Palindromic Concatenation 字符串哈希


    题意:

    题目链接
    给出(n)个字符串,求有多少对((i,j),i eq j)使得(s_i)(s_j)拼起来是回文串

    分析:

    (s_i,s_j)的长度分别为(L_i, L_j),一共有如下三种情况:

    • (L_i=L_j),那么有(s_i)等于(s_j)的反串,(s_i,s_j)构成回文串,注意(s_i)本身是回文串的情况,需要从答案中减去
    • (L_i > L_j),那么有(s_i)的某个后缀是回文串,并且(s_j)是剩余部分的反串
    • (L_i < L_j),分析方法同上

    用两个map<hash, int>分别来记录正串和反串的(hash)
    并且预处理所有字符串的前缀后缀的正串反串的(hash)值,这样就可以(O(1))判断某个前缀后缀是否为回文串
    第一种情况直接计数,对于后两种情况每次枚举较长串的回文前缀和后缀即可

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <string>
    #include <vector>
    #include <map>
    using namespace std;
    #define REP(i, a, b) for(int i = a; i < b; i++)
    #define PER(i, a, b) for(int i = b - 1; i >= a; i--)
    
    typedef long long LL;
    
    const int maxn = 100000 + 10;
    const int MOD[2] = { 1000000007, 1000000009 };
    
    int n;
    
    struct Hash {
        int h[2];
        Hash(int h0 = 0, int h1 = 0) { h[0] = h0; h[1] = h1; }
        Hash(char c) { h[0] = c-'a'+1; h[1] = c-'a'+1; }
        bool operator < (const Hash& t) const {
            return h[0] < t.h[0] || (h[0] == t.h[0] && h[1] < t.h[1]);
        }
        Hash operator * (const Hash& t) const {
            return Hash(1LL * t.h[0] * h[0] % MOD[0], 1LL * t.h[1] * h[1] % MOD[1]);
        }
        Hash operator + (const Hash& t) const {
            return Hash((h[0] + t.h[0]) % MOD[0], (h[1] + t.h[1]) % MOD[1]);
        }
        bool operator == (const Hash& t) const {
            return h[0] == t.h[0] && h[1] == t.h[1];
        }
        void debug() { printf("{ %d, %d }
    ", h[0], h[1]); }
    };
    
    Hash p(1, 1);
    const Hash base(27, 27);
    
    Hash addLeft(const Hash& a, char c) {
        return (Hash(c) * p) + a;
    }
    
    Hash addRight(const Hash& a, char c) {
        return (a * base) + Hash(c);
    }
    
    vector<string> s;
    map<Hash, int> Normal, Reverse;
    vector<Hash> preNormal[maxn], preReverse[maxn], sufNormal[maxn], sufReverse[maxn];
    
    int main() {
        scanf("%d", &n); s.resize(n);
        REP(i, 0, n) {
            cin >> s[i];
            int l = s[i].length();
    
            p = Hash(1, 1);
            preNormal[i].emplace_back(0, 0);
            preReverse[i].emplace_back(0, 0);
            REP(j, 0, l) {
                preNormal[i].push_back(addRight(preNormal[i][j], s[i][j]));
                preReverse[i].push_back(addLeft(preReverse[i][j], s[i][j]));
                p = p * base;
            }
    
            p = Hash(1, 1);
            sufNormal[i].resize(l + 1);
            sufReverse[i].resize(l + 1);
            sufNormal[i][l] = sufReverse[i][l] = Hash(0, 0);
            PER(j, 0, l) {
                sufNormal[i][j] = addLeft(sufNormal[i][j+1], s[i][j]);
                sufReverse[i][j] = addRight(sufReverse[i][j+1], s[i][j]);
                p = p * base;
            }
            Normal[preNormal[i][l]]++;
            Reverse[preReverse[i][l]]++;
        }
    
        LL ans = 0;
        REP(i, 0, n) {
            int l = s[i].length();
    
            //case 1
            if(Reverse.count(preNormal[i][l]))
                ans += Reverse[preNormal[i][l]];
            if(preNormal[i][l] == preReverse[i][l]) ans--;
    
            //case 2
            PER(j, 1, l) if(sufNormal[i][j] == sufReverse[i][j]) {
                if(Reverse.count(preNormal[i][j]))
                    ans += Reverse[preNormal[i][j]];
            }
    
            //case 3
            REP(j, 1, l) if(preNormal[i][j] == preReverse[i][j]) {
                if(Normal.count(sufReverse[i][j]))
                    ans += Normal[sufReverse[i][j]];
            }
        }
    
        cout << ans << endl;
    
        return 0;
    }
    
  • 相关阅读:
    【OpenCV学习笔记5】读取图像中任意点的像素值
    【收藏】国企央企
    Visual Studio 进化史
    【图像算法】不变矩
    工控博客精华链接
    投了...
    【图像算法】常见的数字图像处理程序大全
    Google C++编码规范
    Google员工自述:在哈佛教书和在Google工作的差别
    国立华侨大学校长写给2010届毕业生的话:人生的二和三
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/6612201.html
Copyright © 2020-2023  润新知