您的位置:首页 > 其它

【BZOJ3160】万径人踪灭-FFT+Manacher

2018-03-09 21:23 429 查看
测试地址:万径人踪灭

做法:本题需要用到FFT+Manacher。

这道题要求不连续的回文子序列数量,显然这个数量等于所有回文子序列数量减去连续的回文子序列数量,后面的部分很显然可以用Manacher算法求出,那么现在的问题就是要求出所有回文子序列数量。

对于每条对称轴,都存在一个数kk,使得任意满足i+j=ki+j=k的数对i,ji,j,有ai+ajai+aj关于该对称轴对称。用[U][U]表示表达式UU的真值(00或11),那么关于该对称轴对称且对应字符相同的字符对数为:

⌊(1+∑i+j=k[ai=aj])/2⌋⌊(1+∑i+j=k[ai=aj])/2⌋

将字符aa和bb转化为00和11,那么上面这个式子显然等于:

⌊(1+∑i+j=k[ai=0][aj=0])/2⌋+⌊(1+∑i+j=k[ai=1][aj=1])/2⌋⌊(1+∑i+j=k[ai=0][aj=0])/2⌋+⌊(1+∑i+j=k[ai=1][aj=1])/2⌋

那么令向量AA中的AiAi为[ai=x](x=0,1)[ai=x](x=0,1),那么上面的加号两边的和式很显然是向量卷积的形式了,用FFT优化即可O(nlogn)O(nlog⁡n)计算得出。

那么得到关于某对称轴对称且对应字符相同的字符对数cc后,我们可以得到关于这条对称轴对称的回文子序列数目:2c−12c−1,之所以要减去11是因为我们不把空串计算在内。对于所有对称轴累加上面的值,再减去用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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: