3160: 万径人踪灭
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1753 Solved: 977
[ Submit][ Status][ Discuss]
Description
Input
Output
Sample Input
Sample Output
HINT
Source
FFT板子后的第一次实践~ 这道题要求求不连续的回文子序列(位置对称), 看起来就很不好搞对不对啊~ 所以说我们要考虑补集转化. 这就等于所有回文子序列 - 连续的回文子序列. 后面那个直接可以Manacher来搞. 我们考虑前面那个怎么做.
我们令f[i]表示为在manacher补充#之后的数组s里关于位置i对称并相等的对数. 那么如果x, y要满足这个条件成为一对, 我们会发现这就要求原串里(x / 2) + (y / 2) = i, 因为x / 2和y / 2实际上就是原串位置 + 1(x, y是在s中的). 所以说原串中ss[x]如果等于ss[y], 那么就关于s中x + 1 + y + 1位置对称. 然后就有:
fi=⌊1+∑i−2j=0[sj==si−2−j]2 ⌋
发现是个卷积于是就可以愉快的FFT辣.一开始Manacher写错T了一发身败名裂
#include<bits/stdc++.h>
using namespace std;
typedef long long lnt;
typedef complex<double> C;
const int mod = 1e9 + 7;
const int maxn = 4e5 + 5;
const double pi = acos(-1.0);
lnt ans;
char ss[maxn], s[maxn];
int n, L, rev[maxn], pal[maxn], pw[maxn], f[maxn];
C a[maxn], b[maxn];
inline void FFT(C *a, int f) {
C x, y;
for (int i = 0; i < n; ++ i)
if (rev[i] > i) swap(a[i], a[rev[i]]);
for (int i = 1; i < n; i <<= 1) {
C wn(cos(pi / i), f * sin(pi / i));
for (int j = 0; j < n; j += i << 1) {
C w = 1;
for (int k = 0; k < i; ++ k, w *= wn) {
x = a[j + k], y = w * a[j + k + i];
a[j + k] = x + y, a[j + k + i] = x - y;
}
}
}
}
inline int manacher(char *r) {
int m = 0, mx = 0, id = 0, sum = 0;
for (int i = 0; r[i]; ++ i) s[++ m] = '#', s[++ m] = r[i];
s[0] = '+', s[++ m] = '#';
for (int i = 1; i < m; ++ i) {
if (mx > i) pal[i] = min(mx - i, pal[2 * id - i]);
while (s[i - pal[i]] == s[i + pal[i]]) pal[i] ++;
if (i + pal[i] > mx) mx = pal[i] + i, id = i;
sum = sum + pal[i] / 2;
if (sum > mod) sum -= mod;
}
return sum;
}
int main() {
scanf("%s", ss);
int len = strlen(ss);
register int i;
for (pw[0] = 1, i = 1; i < maxn; ++ i) pw[i] = (pw[i - 1] << 1) % mod;
for (n = 1; n <= len << 1; n <<= 1) L ++;
for (i = 0; i < n; ++ i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (L - 1));
for (i = 0; i < n; ++ i) a[i] = (ss[i] == 'a');
FFT(a, 1);
for (i = 0; i < n; ++ i) b[i] += a[i] * a[i];
for (i = 0; i < n; ++ i) a[i] = (ss[i] == 'b');
FFT(a, 1);
for (i = 0; i < n; ++ i) b[i] += a[i] * a[i];
FFT(b, -1);
for (i = 2; i <= len << 1; ++ i) f[i] += (lnt)(b[i - 2].real() + 0.5) / n;
for (i = 2; i <= len << 1; ++ i) ans = (ans + pw[(f[i] + 1) >> 1] - 1) % mod;
printf("%lld\n", (ans - manacher(ss) + mod) % mod);
return 0;
}