题意:给定一个字符串,求出所有不连续的回文子序列,并且该子序列在原串的位置关于某位置对称。
先忽略掉不连续这个条件,先求出所有的然后减去连续的。
连续的就是回文子串 用Manacher算法可以O(n)求解,(注意这题回文中心可能是在2个字符之间)
所有的情况,要分2种情况,第一个是回文中心是某个字符,另外一个就是在2个字符之间。
考虑到如果s[i-k]=s[i+k],那么这就会对第i个字符产生1的贡献。
如果s[j]=s[k],那么会对(j+k)/2这个位置有1的贡献。
第一种情况,(i-k)+(i+k)=2i,第二种情况j+k。
这好像是个卷积?
所以对ab两种字符分开做,第一种就是s[i]='a',这个位置就是1,否则就是0。第二种情况s[i]='b',这个位置是1否则是0。
然后对这2个多项式进行平方操作(设平方后一个是a一个是b),2个多项式长度*2-1,这时候就相当于在每2个字符中插入一个字符,对于一个项的系数,它的贡献就是2^((a[i]+1)/2+(b[i]+1)/2) -1,这里的除以2都是下取整,对于一个多项式的平方,一个项的系数A[i] = sigma(a[j] * a[i - j]),若是j不等于i-j,那么a[i]和a[i-j]就会被贡献2次,若是i=j,则贡献一次,那么假设i这个位置是1,那么平方后i*2这个位置肯定是个奇数因为i这个位置必然贡献了1。
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 262149;
const double pi = 3.141592653589793238462643383;
const int MOD = 1000000007;
double si[MAXN], co[MAXN];
int n, i, j, k, po[MAXN], m, f[MAXN], bit[MAXN], ans;
char s[MAXN], c[MAXN];
struct sb{
double x, y;
inline friend sb operator * (const sb &a, const sb &b)
{
return (sb){a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x};
}
inline friend sb operator + (const sb &a, const sb &b)
{
return (sb){a.x + b.x, a.y + b.y};
}
inline friend sb operator - (const sb &a, const sb &b)
{
return (sb){a.x - b.x, a.y - b.y};
}
};
sb a[MAXN], b[MAXN];
inline int fft_init(int m)
{
int n = 1, nn = 0;
si[1] = sin(pi * 2.0);
co[1] = cos(pi * 2.0);
while (n < m) n <<= 1, nn ++, si[n] = sin(pi * 2.0 / n), co[n] = cos(pi * 2.0 / n);
for(int i = 0; i < n; i ++)
bit[i] = (bit[i >> 1] >> 1) | ((i & 1) << nn - 1);
return nn;
}
inline void fft(sb *a, int nn, int ty)
{
int n = 1 << nn;
for(int i = 0; i < n; i ++)
if (i < bit[i]) swap(a[i], a[bit[i]]);
for(int k = 1; k <= nn; k ++)
{
int len = 1 << k;
sb wn = (ty == 1) ? (sb){co[len], si[len]} : (sb){co[len], -si[len]};
for(int j = 0; j < n; j += len)
{
int m = len >> 1;
sb w = (sb){1.0, 0.0};
for(int i = j; i < j + m; i ++)
{
sb l = a[i], t = a[i + m] * w;
a[i] = l + t;
a[i + m] = l - t;
w = w * wn;
}
}
}
}
int main()
{
scanf("%s", s);
n = strlen(s);
po[0] = 1;
for(i = 1; i <= 250000; i ++)
po[i] = po[i - 1] * 2 % MOD;
c[0] = '.';
for(i = 0, j = 1; i < n; j ++)
if (j & 1) c[j] = s[i ++];
else c[j] = '.';
int p = 0, mx = 0, N = (n << 1) + 1; f[0] = 0; c[N - 1] = '.';
for(i = 1; i < N; i ++)
{
if (p + mx > i) f[i] = min(f[i - ((i - p) << 1)], p + mx - i);
else f[i] = 0;
while (i - f[i] - 1 >= 0 && f[i] + i + 1 < N && c[i - f[i] - 1] == c[i + f[i] + 1]) f[i] ++;
if (i + f[i] > p + mx) p = i, mx = f[i];
}
for(i = 0; i < N; i ++)
{
ans -= (f[i] + 1 >> 1);
if (ans < 0) ans += MOD;
}
for(i = 0; i < n; i ++)
if (s[i] == 'a') a[i].x = 1;
else b[i].x = 1;
int nn = fft_init(n + n + 1);
N = 1 << nn;
fft(a, nn, 1);
fft(b, nn, 1);
for(i = 0; i < N; i ++)
a[i] = a[i] * a[i], b[i] = b[i] * b[i];
fft(a, nn, -1);
fft(b, nn, -1);
for(i = 0; i < N; i ++)
{
int x = (int)(a[i].x / N + 1.5) >> 1, y = (int)(b[i].x / N + 1.5) >> 1;
ans += po[x + y] - 1;
if (ans < 0) ans += MOD;
if (ans >= MOD) ans -= MOD;
}
cout << ans << endl;
}