【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(nlogn)计算得出。
那么得到关于某对称轴对称且对应字符相同的字符对数cc后,我们可以得到关于这条对称轴对称的回文子序列数目:2c−12c−1,之所以要减去11是因为我们不把空串计算在内。对于所有对称轴累加上面的值,再减去用Manacher算出的回文串数即可得到最终的答案,这样我们就解决了这一题。
以下是本人代码:
做法:本题需要用到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(nlogn)计算得出。
那么得到关于某对称轴对称且对应字符相同的字符对数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; }
相关文章推荐
- bzoj3160 万径人踪灭 FFT+manacher
- BZOJ3160 万径人踪灭 FFT+manacher
- [BZOJ3160]万径人踪灭 FFT+manacher
- bzoj3160: 万径人踪灭 FFT manacher
- BZOJ 3160 万径人踪灭 FFT+Manacher
- BZOJ[3160]万径人踪灭 FFT+Manacher
- 【BZOJ3160】万径人踪灭 FFT manacher
- BZOJ 3160 万径人踪灭【FFT+manacher
- [bzoj3160][FFT][manacher]万径人踪灭
- 【BZOJ3160】万径人踪灭(FFT,Manacher)
- [BZOJ 3160]万径人踪灭(FFT+Manacher)
- 【BZOJ3160】万径人踪灭(FFT,Manacher)
- [bzoj3160] 万径人踪灭 [FFT+manacher]
- 【manacher+FFT】BZOJ3160-万径人踪灭
- BZOJ3160 万径人踪灭(FFT+manacher)
- 【BZOJ3160】万径人踪灭 Manacher+FFT
- [BZOJ3160] 万径人踪灭 - FFT快速傅里叶变换 - manacher
- BZOJ3160 万径人踪灭 【fft + manacher】
- BZOJ3160:万径人踪灭 (manacher+FFT)(占位)
- BZOJ 3160: 万径人踪灭 [fft manacher]