bzoj3160
fft+manacher
fft都快忘了。。。
其实我们发现,这个问题是可以用fft做的,因为是回文子序列,所以我们直接自己和自己求卷积,然后扫描每个位置,注意是每个位置,因为包括奇数长度和偶数长度,f[i]为第i个位置上的对称字符的数量,那么一共就有(2^f[i])-1个回文子序列,因为是要不连续的,所以用manacher求出连续的就行了
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 400010, mod = 1000000007; const double pi = acos(-1); int n, m, pos, mx, len, L; complex<double> a[N], b[N]; int r[N], p[N], f[N]; ll pw[N]; ll ans; char s[N], t[N]; void fft(complex<double> *a, int f) { for(int i = 0; i < n; ++i) if(i < r[i]) swap(a[i], a[r[i]]); for(int i = 1; i < n; i <<= 1) { complex<double> t(cos(pi / i), f * sin(pi / i)); for(int p = i << 1, j = 0; j < n; j += p) { complex<double> w(1, 0); for(int k = 0; k < i; ++k, w *= t) { complex<double> x = a[j + k], y = w * a[j + k + i]; a[j + k] = x + y; a[j + k + i] = x - y; } } } } int main() { scanf("%s", t); n = strlen(t); s[0] = '-'; s[len = 1] = '#'; for(int i = 0; i < n; ++i) s[++len] = t[i], s[++len] = '#'; for(int i = 1; i <= len; ++i) { if(mx > i) p[i] = min(mx - i, p[2 * pos - i]); while(s[i + p[i]] == s[i - p[i]]) ++p[i]; if(i + p[i] > mx) { pos = i; mx = i + p[i]; } ans -= p[i] >> 1; } len = n; m = 2 * n; for(n = 1; n <= m; n <<= 1) ++L; for(int i = 0; i < n; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (L - 1)); for(int i = 0; i < len; ++i) a[i] = (t[i] == 'a' ? 1 : 0), b[i] = (t[i] == 'b' ? 1 : 0); fft(a, 1); fft(b, 1); for(int i = 0; i < n; ++i) a[i] *= a[i], b[i] *= b[i]; fft(a, -1); fft(b, -1); pw[0] = 1ll; for(int i = 1; i <= n; ++i) pw[i] = (pw[i - 1] << 1ll) % mod; for(int i = 0; i < m - 1; ++i) { int x = (int)(a[i].real() / n + 0.5), y = (int)(b[i].real() / n + 0.5); ans = (ans + pw[(x + y + 1) >> 1] - 1) % mod; } printf("%lld\n", ans); return 0; }