# BZOJ3160 万径人踪灭 【fft + manacher】

## 题解

orz po神牛

ans2可以用马拉车轻松解出，这里就不赘述了

$c[n]$表示以$n/2$位置为对称点的对称点对数【n/2若不为整数则对称中心是字符间隙】

$c[n] = \sum a[k]*a[n - k]$，a[k]表示k位置的字符，*运算满足当且仅当两者字符相等时为1，否则为0

①'a'位置赋值0，'b'位置赋值1，求$c[n] = \sum a[k]*b[n - k]$
②'a'位置赋值1，'b'位置赋值0，求$c[n] = \sum a[k]*b[n - k]$

【讲道理分开来求，然后相加应该也行】

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<complex>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
using namespace std;
const int maxn = 800005,maxm = 200005,INF = 1000000000,P = 1000000007;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - '0'; c = getchar();}
return out * flag;
}
char s[maxm],t[maxm];
int RL[maxm],n;
LL ans1,ans2,F,power[maxn];
void manacher(){
s[0] = '*';
int pos = 1,mr = 1; RL[1] = 1;
for (int i = 2; i < n; i++){
if (i <= mr) RL[i] = min(RL[2 * pos - i],mr - i + 1);
else RL[i] = 1;
while (s[i + RL[i]] == s[i - RL[i]]) RL[i]++;
if (i + RL[i] - 1 >= mr) mr = i + RL[i] - 1,pos = i;
}
}
const double pi = acos(-1);
typedef complex<double> E;
E a[maxn],b[maxn];
int m,L,R[maxn];
void fft(E* 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){
E wn(cos(pi / i),f * sin(pi / i));
for (int j = 0; j < n; j += (i << 1)){
E w(1,0);
for (int k = 0; k < i; k++,w *= wn){
E x = a[j + k],y = w * a[j + k + i];
a[j + k] = x + y; a[j + k + i] = x - y;
}
}
}
if (f == -1) for (int i = 0; i < n; i++) a[i] /= n;
}
int main(){
scanf("%s",t + 1); int len = strlen(t + 1);
for (int i = 1; i <= len; i++) s[++n] = '#',s[++n] = t[i]; s[++n] = '#';
manacher();
for (int i = 1; i <= n; i++) ans2 = (ans2 + (RL[i] >> 1)) % P;
//cout<<ans2<<endl;
power[0] = 1; for (int i = 1; i <= n; i++) power[i] = (power[i - 1] << 1) % P;
n = len;
m = n << 1; 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 = 1; i <= len; i++) a[i] = (t[i] == 'a');
fft(a,1);
for (int i = 0; i < n; i++) b[i] = a[i] * a[i];
memset(a,0,sizeof(a));
for (int i = 1; i <= len; i++) a[i] = (t[i] == 'b');
fft(a,1);
for (int i = 0; i < n; i++) b[i] += a[i] * a[i];
fft(b,-1);
for (int i = 1; i < n; i++){
F = (LL)(b[i].real() + 0.5);
ans1 = (ans1 + power[F + 1 >> 1] - 1) % P;
}
//cout<<ans1<<endl;
printf("%lld\n",((ans1 - ans2) % P + P ) % P);
return 0;
}


posted @ 2018-01-25 20:08  Mychael  阅读(156)  评论(0编辑  收藏  举报