【BZOJ3160】万径人踪灭-FFT+Manacher
测试地址:万径人踪灭
做法:本题需要用到FFT+Manacher。
这道题要求不连续的回文子序列数量,显然这个数量等于所有回文子序列数量减去连续的回文子序列数量,后面的部分很显然可以用Manacher算法求出,那么现在的问题就是要求出所有回文子序列数量。
对于每条对称轴,都存在一个数,使得任意满足的数对,有关于该对称轴对称。用表示表达式的真值(或),那么关于该对称轴对称且对应字符相同的字符对数为:
将字符和转化为和,那么上面这个式子显然等于:
那么令向量中的为,那么上面的加号两边的和式很显然是向量卷积的形式了,用FFT优化即可计算得出。
那么得到关于某对称轴对称且对应字符相同的字符对数后,我们可以得到关于这条对称轴对称的回文子序列数目:,之所以要减去是因为我们不把空串计算在内。对于所有对称轴累加上面的值,再减去用Manacher算出的回文串数即可得到最终的答案,这样我们就解决了这一题。
以下是本人代码:
#include <bits/stdc++.h>
#define ll long long
#define mod 1000000007
using namespace std;
const double pi=acos(-1.0);
const double eps=1e-5;
int n,x,r[500010];
ll cnt[500010]={0},len[500010],ans=0;
char s[200010];
struct Complex
{
double x,y;
}a[500010];
Complex operator + (Complex a,Complex b) {Complex s={a.x+b.x,a.y+b.y};return s;}
Complex operator - (Complex a,Complex b) {Complex s={a.x-b.x,a.y-b.y};return s;}
Complex operator * (Complex a,Complex b) {Complex s={a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x};return s;}
ll power(ll a,ll b)
{
ll s=1,ss=a;
while(b)
{
if (b&1) s=(s*ss)%mod;
ss=(ss*ss)%mod;b>>=1;
}
return s;
}
void FFT(Complex *a,int n,int type)
{
for(int i=0;i<n;i++)
if (i<r[i]) swap(a[i],a[r[i]]);
for(int mid=1;mid<n;mid<<=1)
{
Complex W={cos(pi/mid),type*sin(pi/mid)};
for(int l=0;l<n;l+=(mid<<1))
{
Complex w={1.0,0.0};
for(int k=0;k<mid;k++,w=w*W)
{
Complex x=a[l+k],y=w*a[l+mid+k];
a[l+k]=x+y;
a[l+mid+k]=x-y;
}
}
}
if (type==-1)
{
for(int i=0;i<n;i++)
a[i].x/=n;
}
}
void Manacher()
{
for(int i=n-1;i>=0;i--)
{
s[(i<<1)+2]='#';
s[(i<<1)+1]=s[i];
}
s[0]='#';
len[1]=1;
int dis=1,mid=1;
for(int i=2;i<(n<<1);i++)
{
if (i>dis||i+len[(mid<<1)-i]>=dis)
{
len[i]=max(0,dis-i);
while(len[i]<i&&s[i+len[i]+1]==s[i-len[i]-1]) len[i]++;
mid=i;dis=i+len[i];
}
else if (i+len[(mid<<1)-i]<dis) len[i]=len[(mid<<1)-i];
}
}
int main()
{
scanf("%s",s);
n=strlen(s);
memset(a,0,sizeof(a));
for(int i=0;i<n;i++)
if (s[i]=='a') a[i].x=1.0;
int bit=0,x=1;
while(x<(n<<1)) x<<=1,bit++;
r[0]=0;
for(int i=1;i<x;i++)
r[i]=(r[i>>1]>>1)|((i&1)<<(bit-1));
FFT(a,x,1);
for(int i=0;i<x;i++)
a[i]=a[i]*a[i];
FFT(a,x,-1);
for(int i=0;i<(n<<1)-1;i++)
{
cnt[i]+=((ll)(a[i].x+eps)+1)/2;
}
memset(a,0,sizeof(a));
for(int i=0;i<n;i++)
if (s[i]=='b') a[i].x=1.0;
FFT(a,x,1);
for(int i=0;i<x;i++)
a[i]=a[i]*a[i];
FFT(a,x,-1);
for(int i=0;i<(n<<1)-1;i++)
{
cnt[i]+=((ll)(a[i].x+eps)+1)>>1;
ans=(ans+(power(2,cnt[i])-1+mod)%mod)%mod;
}
Manacher();
for(int i=1;i<(n<<1);i++)
ans=(ans-((len[i]+1)>>1)+mod)%mod;
printf("%lld",ans);
return 0;
}