1. 程式人生 > >[Luogu P4199] [BZOJ 3160] 萬徑人蹤滅

[Luogu P4199] [BZOJ 3160] 萬徑人蹤滅

洛谷傳送門

img

img

img

解題分析

很容易想到: 方案數==迴文序列個數-迴文串個數。

迴文串我們用manachermanacher搞出來就好了, 關鍵是迴文序列數。

聯絡到我們寫萬用字元匹配時的套路, 如果第ii個字元和第jj個字元相同,我們以i+12\frac{i+1}{2}為中心情況的貢獻cnt[i]cnt[i]就會+1+1

這個分數很討厭, 我們就把這個貢獻加在i+ji+j就好, 最後答案就為i=1n×2(2cnt[i]1)\sum_{i=1}^{n\times 2}(2^{cnt[i]}-1)

(需要去掉空序列的情況)。

cnt[]cnt[]這玩意顯然是個卷積的形式, 可以通過自己和自己FFTFFT得到, 完美ACAC

注意計算的時候加上EPSEPS, 誤差較大。

程式碼如下:

#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); }