• 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!
  • 相关阅读:
    .NET 事件模型教程(一)
    [转帖]Predicate的用法
    MSBuild入门(续)
    浅析C# 中object sender与EventArgs e
    调用一个按钮的Click事件(利用反射)
    Delegate,Action,Func,匿名方法,匿名委托,事件
    投票系统如何防止一个用户多次投票
    如何发送表单
    SharePoint NLB选Unicast还是选Multicast?
    为SharePoint的多台WFE配置Windows自带的NLB遇到的一个问题
  • 原文地址:https://www.cnblogs.com/wethura/p/9898071.html
Copyright © 2020-2023  润新知