"蔚来杯"2022牛客暑期多校训练营9 G Magic Spells【马拉车+哈希】

四川今天又上热搜了,继南部疫情的未雨绸缪后,龙槽沟是真的倾盆大雨了。我没有兴趣虚伪矫情地对罹难的游人表达同情,因为人与人互不相通徒增谈资;我也没有兴趣居高临下地对擅闯的愚人表达不屑,因为你我皆为乌合之众,在流媒体的灯红酒绿下娱乐至死。地球上最聪明的大脑像条二极管,只能接受最简单的二元判断,稍微复杂的变量就足以使之熔断。基层工作人员与群众大抵是存在着些割裂的,只要就着喇叭喊叫,就一定是在表达“认同你”或“否定你”其一,绝无“陈述事实”一说。学了几十年逻辑,还是顺应情绪,不断窥视大众行为决断,也是,法不责众嘛。有人扭曲身形挤进人群刷安全感,有人刻意和大众对立谋求优越感,殊途原来也是可以同归的呵。

亚当夏娃唉声叹气
达尔文骂骂咧咧地投靠上帝
hash求子串可以O(1),

$click$ $for$ $codes$
# include "bits/stdc++.h"
using namespace std;
constexpr int N = 3e5 + 3;
char str[N], str_new[N << 1];
int main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int n;
    cin >> n;
    unordered_map<unsigned long long, int> mp;
    unordered_map<unsigned long long, int> mp2;
    unordered_map<unsigned long long, bool> vis[6];
    unordered_map<unsigned long long, bool> vis2[6];
    int ans = 0;
    str_new[0] = '!';
    str_new[1] = '@';
    for(int i = 1; i <= n; ++i) {
        cin >> str + 1;
        int len = strlen(str + 1);
        int len_new = 1;
        for(int j = 1; j <= len; ++j) {
            str_new[++len_new] = str[j];
            str_new[++len_new] = '@';
        }
        str_new[++len_new] = '#';
        int r = 0, center;
        vector<int> p(len_new + 1 << 1);
        vector<int> pos;
        for(int j = 1; j <= len_new; ++j) {
            p[j] = (j < r) ? min(p[(center << 1) - j], r - j) : 1;
            while(str_new[j - p[j]] == str_new[j + p[j]]) ++p[j];
            if(r < j + p[j]) {
                r = j + p[j];
                center = j;
            }
            if(p[j] > 1) pos.push_back(j);
        }
         
        constexpr unsigned long long base = 122777, mod = 91815541, mod2 = 19260817; // hash value, which is indescibable
        vector<unsigned long long> h(len + 1), b(len + 1), h2(len + 1), b2(len + 1);
        b[0] = 1, b2[0] = 1;
        for(int i = 1; i <= len; ++i) {
        	h[i] = (h[i - 1] * base % mod + (unsigned long long) str[i]) % mod;
        	h2[i] = (h2[i - 1] * base % mod2 + (unsigned long long) str[i]) % mod2;
        	b[i] = b[i - 1] * base % mod;
        	b2[i] = b2[i - 1] * base % mod2;
		}
		auto hash = [&](int l, int r) -> unsigned long long {
			return (h[r] - h[l - 1] * (unsigned long long)b[r - l + 1] % mod + mod) % mod;
		};
		auto hash2 = [&](int l, int r) -> unsigned long long { // double hash reduces chance and thus improves accuracy
			return (h2[r] - h2[l - 1] * (unsigned long long)b2[r - l + 1] % mod2 + mod2) % mod2;
		};
        for(auto j : pos) {
            int len = p[j];
            while(len) {
            	if((j - len + 2 >> 1) > (j + len - 2 >> 1)) break; // from several manual simulations, we'll find that the palindrome string centered on i in the new string is (i - p[i】 + 2) / 2 ---> (i + p[i] - 2) / 2 in the corresponding position in the original string
                unsigned long long sub_str_1 = hash( (j - len + 2 >> 1), (j + len - 2 >> 1) );
                unsigned long long sub_str_2 = hash2( (j - len + 2 >> 1), (j + len - 2 >> 1) );
                if(vis[i][sub_str_1] == true && vis2[i][sub_str_2] == true) break;
                vis[i][sub_str_1] = vis2[i][sub_str_2] = true;
                ++mp[sub_str_1], ++mp2[sub_str_2];
                if(mp[sub_str_1] >= n && mp2[sub_str_2] >= n) ++ ans;
                len -= 2; // manachar only directly finds the longest palindrome string, but the string may contain other substrings
                if(len < 0) break;
            }
        }
    }
 
    cout << ans;
    return 0;
}
/*
9999
abcba
abcccba
*/

image

posted @ 2022-08-15 22:09  邱涵的秘密基地  阅读(90)  评论(0编辑  收藏  举报