zoukankan      html  css  js  c++  java
  • Interesting (manacher + 前缀和处理)

      题意:相邻的两端回文串的价值为两个回文串总的区间左端点 × 区间右端点。然后计算目标串中所有该情况的总和。

      思路:首先用manacher求出所有中心点的最大半径,然后我们知道对于左区间我们把贡献记录在右端点,右区间记录在左端点。然后细节的我就不太懂了。迷~

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn = 2e6 +7;
    const int mod  = 1e9 + 7;
    long long rad[maxn], L[maxn], R[maxn], cnt1[maxn], cnt2[maxn];
    char in[maxn], str[maxn];
    
    void manacher(){
        int len = strlen(in), l = 0;
        str[l ++] = '$'; str[l ++] = '#';
        for(int i = 0; i < len; i ++)
            str[l ++] = in[i], str[l ++] = '#';
        str[l] = 0;
        int mx = 0, id = 0;
        for(int i = 0; i < l; i ++) {
            rad[i] = mx > i ? min(rad[2 * id - i], 1LL * mx - i) : 1;
            while(str[i + rad[i]] == str[i - rad[i]]) rad[i] ++;
            if(i + rad[i] > mx){
                mx = i + rad[i];
                id = i;
            }
        }
    }
    
    int main(){
    
        while(~scanf("%s", in)) {
            int len = strlen(in);
            manacher();
    //        for(int i = 0; i < 2 * len + 2; i ++) printf(" %d ", rad[i]);
            memset(cnt1, 0, sizeof(cnt1));
            memset(cnt2, 0, sizeof(cnt2));
            for(int i = 1; i <= 2 * len; i ++){
                cnt1[i - rad[i] + 1] += i; cnt1[i + 1] -= i;
                cnt2[i - rad[i] + 1] ++; cnt2[i + 1] --;
            }
            for(int i = 1; i <= 2 * len; i ++){
                cnt1[i] += cnt1[i - 1], cnt2[i] += cnt2[i - 1];
                if(i % 2 == 0) R[i/2] = (cnt1[i] - i / 2 * cnt2[i]) % mod;
            }
            memset(cnt1, 0, sizeof(cnt1));
            memset(cnt2, 0, sizeof(cnt2));
            for(int i = 1; i <= 2 * len; i ++) {
                cnt1[i + rad[i]] -= i; cnt1[i] += i;
                cnt2[i + rad[i]] --; cnt2[i] ++;
            }
            for(int i = 1; i <= 2 * len; i ++) {
                cnt1[i] += cnt1[i - 1]; cnt2[i] += cnt2[i - 1];
                if(i % 2 == 0) L[i / 2] = (cnt1[i] - i / 2 * cnt2[i]) % mod;
            }
            long long ans = 0;
            for(int i = 0; i < len; i ++) ans = (ans + L[i] * R[i + 1] % mod) % mod;
            printf("%lld
    ", ans);
        }
        return 0;
    }
    more crazy more get!
  • 相关阅读:
    OSI安全体系结构
    PHP 二维数组根据相同的值进行合并
    Java实现 LeetCode 17 电话号码的字母组合
    Java实现 LeetCode 16 最接近的三数之和
    Java实现 LeetCode 16 最接近的三数之和
    Java实现 LeetCode 16 最接近的三数之和
    Java实现 LeetCode 15 三数之和
    Java实现 LeetCode 15 三数之和
    Java实现 LeetCode 15 三数之和
    Java实现 LeetCode 14 最长公共前缀
  • 原文地址:https://www.cnblogs.com/wethura/p/9898071.html
Copyright © 2011-2022 走看看