题意
给定一个由’a’和’b’构成的字符串,求不连续回文子序列的个数。
题解
正难则反我们考虑容斥。对于连续的回文字串显然是一次马拉车就可以很好的求出来的,那我们设f[i]表示以i为中心的对称字符对数量,显然答案就是
∑2∗n+112f[i]−1
那么我们的问题就转变成了怎么求出f[i]
我们考虑当这个字符为a的时候做一遍fft,为b的时候再做一遍就好
代码
#include <bits/stdc++.h>
#define pi acos(-1)
const int inf = 1000000000;
const int MOD = 1e9 + 7;
const int N = 400010;
using namespace std;
typedef long long ll;
typedef complex<double> E;
ll ans;
int n,m,L;
E a[N],b[N];
int rev[N];
ll f[N],bin[N];
char s[N],st[N];
int p[N];
void FFT(E *a,int f)
{
for (int i = 0; i < n; i++)
if (i < rev[i])
swap(a[i],a[rev[i]]);
for (int i = 1; i < n; i <<= 1)
{
E wn(cos(pi / i), f * sin(pi / i));
for (int p = i << 1, j = 0; j < n; j += p)
{
E w(1, 0);
for (int k = 0; k < i; k++, w *= wn)
{
E x = a[k + j], y = a[k + j + i] * w;
a[k + j] = x + y; a[k + j + i] = x - y;
}
}
}
}
int Manacher(char *r,int len)
{
st[0] = '$'; st[1] = '#';
for (int i = 0; i < len; i++)
{
st[(i + 1) << 1] = r[i];
st[(i + 1) << 1 | 1] = '#';
}
int mx = 0, id, tot = 0;
for (int i = 1; i < 2 * len + 1; i++)
{
if (i < mx)
p[i] = min(mx - i, p[id * 2 - i]);
while (st[i + p[i]] == st[i - p[i]])
p[i]++;
if (p[i] + i > mx)
mx = p[i] + i, id = i;
tot = (tot + p[i] / 2) % MOD;
}
return tot;
}
int main()
{
scanf("%s",s);
int len = strlen(s);
bin[0] = 1;
for (int i = 1; i < N; i++)
bin[i] = (bin[i - 1] << 1) % MOD;
for (n = 1; n <= len << 1; n <<= 1)
L++;
for (int i = 0; i < n; i++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (L - 1));
for (int i = 0; i < len; i++)
{
if (s[i] == 'a')
a[i] = 1;
else a[i] = 0;
}
FFT(a, 1);
for (int i = 0; i < n; i++)
b[i] = a[i] * a[i];
memset(a,0,sizeof(a));
for (int i = 0; i < len; i++)
{
if (s[i] == 'b')
a[i] = 1;
else a[i] = 0;
}
FFT(a,1);
for (int i = 0; i < n; i++)
b[i] += a[i] * a[i];
FFT(b,-1);
ll ans = 0;
for (int i = 2; i < 2 * len + 1; i++)
f[i] += (ll)(b[i - 2].real() + 0.5) / n;
for (int i = 2; i < 2 * len + 1; i++)
ans = (ans + bin[(f[i] + 1) >> 1] - 1) % MOD;
printf("%lld",(ans + MOD - Manacher(s,len)) % MOD);
return 0;
}