[Luogu P4199] [BZOJ 3160] 萬徑人蹤滅
阿新 • • 發佈:2018-12-13
洛谷傳送門
解題分析
很容易想到: 方案數迴文序列個數-迴文串個數。
迴文串我們用搞出來就好了, 關鍵是迴文序列數。
聯絡到我們寫萬用字元匹配時的套路, 如果第個字元和第個字元相同,我們以為中心情況的貢獻就會。
這個分數很討厭, 我們就把這個貢獻加在就好, 最後答案就為(需要去掉空序列的情況)。
這玩意顯然是個卷積的形式, 可以通過自己和自己得到, 完美。
注意計算的時候加上, 誤差較大。
程式碼如下:
#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);
}