1. 程式人生 > >Interesting (manacher + 字首和處理)

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\n", ans); } return 0; }