洛谷传送门
BZOJ传送门
解题分析
很容易想到: 方案数 = = =回文序列个数-回文串个数。
回文串我们用 m a n a c h e r manacher manacher搞出来就好了, 关键是回文序列数。
联系到我们写通配符匹配时的套路, 如果第 i i i个字符和第 j j j个字符相同,我们以 i + 1 2 \frac{i+1}{2} 2i+1为中心情况的贡献 c n t [ i ] cnt[i] cnt[i]就会 + 1 +1 +1。
这个分数很讨厌, 我们就把这个贡献加在 i + j i+j i+j就好, 最后答案就为 ∑ i = 1 n × 2 ( 2 c n t [ i ] − 1 ) \sum_{i=1}^{n\times 2}(2^{cnt[i]}-1) ∑i=1n×2(2cnt[i]−1)(需要去掉空序列的情况)。
c n t [ ] cnt[] cnt[]这玩意显然是个卷积的形式, 可以通过自己和自己 F F T FFT FFT得到, 完美 A C AC AC。
注意计算的时候加上 E P S EPS EPS, 误差较大。
代码如下:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 800500
#define db double
#define MOD 1000000007
#define EPS 0.1
const db PI = std::acos(-1.0);
struct Complex {db im, re;} a[MX], b[MX];
IN Complex operator * (const Complex &x, const Complex &y) {return {x.im * y.re + x.re * y.im, x.re * y.re - x.im * y.im};}
IN Complex operator + (const Complex &x, const Complex &y) {return {x.im + y.im, x.re + y.re};}
IN Complex operator - (const Complex &x, const Complex &y) {return {x.im - y.im, x.re - y.re};}
int rev[MX], ans[MX], pw[MX], cnt[MX];
int len, mid, pos, tot, lg, res;
char buf[MX], val[MX];
IN void FFT(Complex *dat, const int &typ)
{
for (R int i = 0; i < tot; ++i) if(rev[i] > i) std::swap(dat[rev[i]], dat[i]);
R int seg, bd, now, cur, step;
Complex base, deal, buf1, buf2;
for (seg = 1; seg < tot; seg <<= 1)
{
base = {std::sin(PI / seg) * typ, std::cos(PI / seg)}; step = seg << 1;
for (now = 0; now < tot; now += step)
{
deal = {0, 1}, bd = now + seg;
for (cur = now; cur < bd; ++cur, deal = deal * base)
{
buf1 = dat[cur], buf2 = dat[cur + seg] * deal;
dat[cur] = buf1 + buf2, dat[cur + seg] = buf1 - buf2;
}
}
}
}
IN int manacher()
{
int ret = 0, bd = (len << 1) + 1;
val[0] = '$'; val[1] = '#';
for (R int i = 2; i <= bd; ++i)
if(i & 1) val[i] = '#'; else val[i] = buf[(i >> 1) - 1];
mid = 0, pos = 0;
for (R int i = 1; i <= bd; ++i)
{
if(i < pos) ans[i] = std::min(ans[2 * mid - i], pos - i);
else ans[i] = 1;
W (val[i + ans[i]] == val[i - ans[i]]) ++ans[i];
if(pos < ans[i] + i) mid = i, pos = ans[i] + i;
ret = (ret + ans[i] / 2) % MOD;
}
return ret;
}
int main(void)
{
scanf("%s", buf); len = std::strlen(buf);
for (tot = pw[0] = 1; tot < len; tot <<= 1, ++lg); ++lg, tot <<= 1;
for (R int i = 1; i < tot; ++i) pw[i] = pw[i - 1] * 2 % MOD;
for (R int i = 1; i < tot; ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (lg - 1));
for (R int i = 0; i < len; ++i) (buf[i] == 'a') ? (a[i].re = 1) : (b[i].re = 1);
FFT(a, 1), FFT(b, 1);
for (R int i = 0; i < tot; ++i) a[i] = a[i] * a[i], b[i] = b[i] * b[i];
FFT(a, -1), FFT(b, -1);
for (R int i = 0; i < tot; ++i) cnt[i] = (((int)((a[i].re + b[i].re) / tot + EPS) + 1) / 2);
for (R int i = 0; i < tot; ++i) res = (res + pw[cnt[i]] - 1) % MOD;
printf("%d", (res - manacher() + MOD) % MOD);
}