[bzoj3160][FFT][manacher]万径人踪灭
来源:互联网 发布:汉宫外设淘宝店网址 编辑:程序博客网 时间:2024/06/05 05:41
题意
给定一个由a和b构成的串,求不连续回文子串的个数
输入
输入一个只由a和b组成的字符串
输出
输出不连续回文子串的个数
数据范围与规定
字符串长度<=100000
题解
首先先考虑回文串,很容易想到manacher,但是这里要求的是不连续的子串,How can you do it?????
设p[i]为 以i为对称轴,相等的两个字符共有多少个
例如ababa
那么p[3]=2
所以说以i为中心 回文串总个数有(2^p[i])-1这么多个
for一遍加起来再减掉manacher算出的连续回文串就好了
剩下的就是如何快速求出p数组了
按照manacher的思路,先加上分隔符
@a@b@a@b@a@(因为csdn里不能用#所以我就@了。。)
观察两个b,发现他们在原数组中位置分别为2和4
2+4=6
有点神奇哦。。好像加起来后这个下标是加了分隔符后第三个a的位置
那么可以大胆考虑,p[i]=(Σ[1<=j<=i-1]bool(str[j]==str[i-j]))+1>>1
里面是个卷积。可以fft优化
观察n的范围,10^5的数据,哇真的要用fft优化耶
这么神奇的推fft。。我%%%%
#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>#include<cmath>using namespace std;typedef long long LL;const LL mod=1000000007;const double PI=acos(-1.0);const int MAXN=263000;struct Complex{ double r,i;//real imag Complex() {} Complex(double _r,double _i){r=_r;i=_i;} friend Complex operator + (const Complex &x,const Complex &y){return Complex(x.r+y.r,x.i+y.i);} friend Complex operator - (const Complex &x,const Complex &y){return Complex(x.r-y.r,x.i-y.i);} friend Complex operator * (const Complex &x,const Complex &y){return Complex(x.r*y.r-x.i*y.i,x.r*y.i+x.i*y.r);}}a[MAXN],b[MAXN];int R[MAXN],L,m,p[MAXN];LL ans,tmp[MAXN],list[MAXN];char s[MAXN],now[MAXN];void fft(Complex *y,int len,int on){ for(int i=0;i<len;i++)if(i<R[i])swap(y[i],y[R[i]]); for(int i=1;i<len;i<<=1)//枚举需要合并的长度 合并后的长度就成了i*2对吧。所以无需枚举至len { Complex wn(cos(PI/i),sin(on*PI/i));//无需乘2,因为合并后长度i*2,用到的单位复数根只有i for(int j=0;j<len;j+=(i<<1))//被分成了L/(i<<1)段序列 { Complex w(1,0);//注意一点,w是在for循环执行完毕后才累乘,因为我们还有w^0对吧 for(int k=0;k<i;k++,w=w*wn)//枚举前半部分,后半部分加上一个i就可以了嘛 { Complex u=y[j+k];//j+k即是前半部分 Complex v=w*y[j+k+i];//j+k+i即是后半部分 y[j+k]=u+v; y[j+k+i]=u-v; } } } if(on==-1)for(int i=0;i<len;i++)y[i].r/=len;//IFFT 每个数都要/len }int manacher(){ LL ss=0; for(int i=1;i<=m;i++)now[2*i-1]='#',now[2*i]=s[i-1]; m=2*m+1; now[m]='#'; int k=0,r=0; for(int i=1;i<=m;i++) { int j=k-(i-k);//i以k为中心的对称点 if(i<=r) { if(p[j]<r-i+1)p[i]=p[j]; else p[i]=r-i+1; } else p[i]=1; while(i-p[i]>=1 && i+p[i]<=m && now[i-p[i]]==now[i+p[i]])p[i]++; if(i+p[i]-1>r){k=i;r=i+p[i]-1;} ss=(ss+p[i]/2)%mod; } return ss;}void gettmp(){ tmp[0]=1; for(int i=1;i<MAXN;i++)tmp[i]=(tmp[i-1]*2)%mod;}int main(){ scanf("%s",s); m=strlen(s); L=0;int len; for(len=1;len<=m*2;len<<=1)L++; for(int i=0;i<len;i++)R[i]=(R[i>>1]>>1)|(i&1)<<(L-1); for(int i=0;i<m;i++)if(s[i]=='a')a[i]=Complex(1,0); fft(a,len,1); for(int i=0;i<len;i++)b[i]=b[i]+(a[i]*a[i]); for(int i=0;i<len;i++) { if(s[i]=='b')a[i]=Complex(1,0); else a[i]=Complex(0,0); } fft(a,len,1); for(int i=0;i<len;i++)b[i]=b[i]+(a[i]*a[i]); fft(b,len,-1); LL del=manacher(); for(int i=0;i<len;i++)list[i]=(LL)(b[i].r+0.5); ans=0;gettmp(); for(int i=1;i<len;i++)ans=(ans+tmp[list[i]+1>>1]-1)%mod; printf("%lld\n",(ans-del+mod+1)%mod); return 0;}
阅读全文
0 0
- bzoj3160 万径人踪灭(FFT+manacher)
- bzoj3160 万径人踪灭 FFT+manacher
- 【bzoj3160】万径人踪灭 FFT+manacher
- BZOJ3160 万径人踪灭 FFT+manacher
- 【BZOJ3160】万径人踪灭 FFT manacher
- BZOJ3160: 万径人踪灭 FFT+manacher
- [bzoj3160][FFT][manacher]万径人踪灭
- [BZOJ3160]万径人踪灭 FFT+manacher
- [BZOJ3160]万径人踪灭(FFT+manacher)
- BZOJ3160:万径人踪灭 (FFT+Manacher)
- [BZOJ3160] 万径人踪灭 - FFT快速傅里叶变换 - manacher
- [BZOJ3160]万径人踪灭-快速傅里叶变换-Manacher算法
- 3160: 万径人踪灭|FFT|manacher
- BZOJ3160(NTT+manacher)
- BZOJ 3160 万径人踪灭 FFT+Manacher
- BZOJ 3160 万径人踪灭【FFT+manacher
- bzoj3160: 万径人踪灭
- bzoj3160 万径人踪灭
- 浅读《JavaScript 高级程序设计》第四章
- Chapter 4 神经网络
- How JavaScript works: inside the V8 engine + 5 tips on how to write optimized code
- 图像处理之均值滤波介绍及C算法实现
- js对于加载跟多滚动条的位置相关
- [bzoj3160][FFT][manacher]万径人踪灭
- 360提示证书风险问题
- 构造函数
- 高阶函数(一)
- C语言经典算法100例
- 购买搬瓦工 VPS 服务器
- uva 11584 Partitioning by Palindromes (动态规划)
- GDI+ 的使用
- 扫地僧身份解析