题意:相邻的两端回文串的价值为两个回文串总的区间左端点 × 区间右端点。然后计算目标串中所有该情况的总和。
思路:首先用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; }