BZOJ 3160 万径人踪灭
题面
题目大意
略.
题解
FFT跑一遍, 由于不能连续, 因此再跑一次manacher减去不符合题意的部分.
这道题体现了FFT的一种用途: 在序列中元素个数不多的情况下, 找关于某个中心对称的相同字符.
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cstdlib>
const int N = (int)1e5, MOD = (int)1e9 + 7;
namespace convolution
{
struct complex
{
double rl, img;
inline complex() {}
inline complex(double _rl, double _img)
{
rl = _rl, img = _img;
}
inline complex friend operator +(complex a, complex b)
{
return complex(a.rl + b.rl, a.img + b.img);
}
inline complex friend operator -(complex a, complex b)
{
return complex(a.rl - b.rl, a.img - b.img);
}
inline complex friend operator *(complex a, complex b)
{
return complex(a.rl * b.rl - a.img * b.img, a.rl * b.img + b.rl * a.img);
}
}A[N << 2], B[N << 2];
int len;
int rev[N << 2];
inline void initialize(int n)
{
len = 1;
int tmp = 0;
for(; len < n << 1; len <<= 1, ++ tmp);
rev[0] = 0;
for(int i = 1; i < len; ++ i)
rev[i] = rev[i >> 1] >> 1 | (i & 1) << (tmp - 1);
}
double PI = acos(-1);
inline void FFT(complex *a, int opt)
{
for(int i = 0; i < len; ++ i)
if(rev[i] < i)
std::swap(a[i], a[rev[i]]);
for(int i = 2; i <= len; i <<= 1)
{
complex omg_i = complex(cos(2 * PI * opt / i), sin(2 * PI * opt / i));
for(int j = 0; j < len; j += i)
{
complex omg = complex(1, 0);
for(int k = j; k < j + i / 2; ++ k)
{
complex u = a[k], t = omg * a[k + i / 2];
a[k] = u + t, a[k + i / 2] = u - t;
omg = omg * omg_i;
}
}
}
if(opt == -1)
for(int i = 0; i < len; ++ i)
a[i].rl /= len;
}
inline void work(int *a, int *b, int n, int *res)
{
initialize(n);
memset(A, 0, sizeof(A)), memset(B, 0, sizeof(B));
for(int i = 0; i < n; ++ i)
A[i] = complex(a[i], 0);
for(int i = 0; i < n; ++ i)
B[i] = complex(b[i], 0);
FFT(A, 1), FFT(B, 1);
for(int i = 0; i < len; ++ i)
A[i] = A[i] * B[i];
FFT(A, -1);
memset(res, 0, sizeof(res));
for(int i = 0; i < len; ++ i)
res[i] = round(A[i].rl);
}
}
int pw[N << 1];
inline void getPower()
{
pw[0] = 1;
for(int i = 1; i < N << 2; ++ i)
pw[i] = (long long)pw[i - 1] * 2 % MOD;
}
namespace manacher
{
int a[N << 1 | 1], p[N << 1 | 1];
inline int work(char *str, int len)
{
memset(a, 0, sizeof(a));
a[0] = '#';
for(int i = 0; i < len; ++ i)
a[i << 1 | 1] = str[i], a[i + 1 << 1] = '#';
a[len + 1 << 1] = '#';
len = len << 1 | 1;
int mx = 0, id = 0;
for(int i = 0; i < len; ++ i)
{
p[i] = mx > i ? std::min(mx - i, p[(id << 1) - i]) : 1;
for(; i >= p[i] && i + p[i] < len && a[i - p[i]] == a[i + p[i]]; ++ p[i]);
if(p[i] + i > mx)
mx = p[i] + i, id = i;
}
int ans = 0;
for(int i = 0; i < len; ++ i)
ans = (ans + (p[i] >> 1)) % MOD;
return ans;
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("BZOJ3160.in", "r", stdin);
freopen("BZOJ3160.out", "w", stdout);
#endif
static char str[N];
scanf("%s", str);
int n = strlen(str);
static int a[N];
static int res1[N << 2], res2[N << 2], res[N << 2];
memset(a, 0, sizeof(a));
for(int i = 0; i < n; ++ i)
a[i] = str[i] == 'a';
convolution::work(a, a, n, res1);
memset(a, 0, sizeof(a));
for(int i = 0; i < n; ++ i)
a[i] = str[i] == 'b';
convolution::work(a, a, n, res2);
for(int i = 0; i < n << 1; ++ i)
res[i] = res1[i] + res2[i] + 1 >> 1;
getPower();
int ans = 0;
for(int i = 0; i < n << 1; ++ i)
ans = (ans + pw[res[i]] - 1) % MOD;
printf("%d\n", (ans - manacher::work(str, n) + MOD) % MOD);
}