[bzoj3160]万径人踪灭
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[bzoj3160]万径人踪灭相关的知识,希望对你有一定的参考价值。
Manacher+FFT,这题太精妙了,我现在才写是不是太弱了...
Ans=以某个轴为中心的每一种回文子序列-所有连续回文串方案数
连续部分可以用Manacher在O(n)时间内解决。
第一部分:令f[i]=以i为中轴的对称对数,则对(2^f[i])-1求和即可(不能光有一根轴)
长串中i左右对称的对数位置相加一定是i(在短串中),那么f[i]=[sigma((str[x]==str[i-x])(x<i))+1]/2
这时题目还有个条件哟~串只是由a,b构成的,我们考虑一个卷积的形式C[k]=sigma(a[x]*b[k-x],0<=x<=k),与上面是如出一辙的,只需分别考虑a,b的贡献做两个FFT。
能独立推出来的人都是大大大神....Orz PoPoQQQ!
细节还是有点多,特别要注意长串与短串的下标(有没有插特殊符号)。
1 #include<cstdio> 2 #include<cmath> 3 #include<complex> 4 #include<cstring> 5 #include<algorithm> 6 #define ll long long 7 #define N 502020 8 #define mo 1000000007 9 using namespace std; 10 typedef complex<double> E; 11 const double pi=acos(-1); 12 int n,m,len,p[N],R[N],L; 13 char str[N]; 14 ll ans=0,ans1=0,bin[N]; 15 E a[N],f[N],g[N]; 16 void manacher(){ 17 str[0]=‘-‘;str[len+1]=‘+‘; 18 int id,mx=0; 19 for(int i=1;i<=len;i++){ 20 if(mx>i)p[i]=min(mx-i+1,p[2*id-i]);else p[i]=1; 21 while(str[i+p[i]]==str[i-p[i]])p[i]++; 22 if(i+p[i]-1>mx)mx=i+p[i]-1,id=i; 23 ans1=(ans1+p[i])%mo; 24 }id=0,mx=0; 25 for(int i=1;i<=len;i++){ 26 if(mx>i)p[i]=min(mx-i,p[2*id-i]);else p[i]=0; 27 while(str[i+p[i]+1]==str[i-p[i]])p[i]++; 28 if(i+p[i]>mx)mx=i+p[i],id=i; 29 ans1=(ans1+p[i])%mo; 30 } 31 } 32 void fft(E *a,int f){ 33 for(int i=1;i<n;i++)if(i>R[i])swap(a[i],a[R[i]]); 34 for(int i=1;i<n;i<<=1){ 35 E wn(cos(pi/i),sin(pi/i)*f); 36 for(int j=0;j<n;j+=i<<1){ 37 E w(1,0); 38 for(int k=0;k<i;k++,w*=wn){ 39 E x=a[j+k],y=w*a[j+k+i]; 40 a[j+k]=x+y;a[j+k+i]=x-y; 41 } 42 } 43 } 44 if(f==-1)for(int i=0;i<n;i++)a[i]/=n; 45 } 46 int main() 47 { 48 scanf("%s",str+1);len=strlen(str+1); 49 bin[0]=1;for(int i=1;i<=100000;i++)bin[i]=bin[i-1]*2%mo; 50 manacher(); 51 m=2*(len-1);for(n=1;n<=m;n*=2)L++; 52 for(int i=1;i<n;i++)R[i]=(R[i/2]/2)|((i&1)<<(L-1)); 53 for(int i=0;i<len;i++)a[i]=(str[i+1]==‘a‘); 54 fft(a,1);for(int i=0;i<n;i++)f[i]=a[i]*a[i];fft(f,-1); 55 memset(a,0,sizeof(a)); 56 for(int i=0;i<len;i++)a[i]=(str[i+1]==‘b‘); 57 fft(a,1);for(int i=0;i<n;i++)g[i]=a[i]*a[i];fft(g,-1); 58 for(int i=0;i<n;i++){ 59 int x=f[i].real()+g[i].real()+0.1; 60 ans=(ans+bin[(x+1)/2])%mo; 61 ans=(ans-1+mo)%mo; 62 } 63 //printf("%lld %lld\n",ans,ans1); 64 printf("%lld\n",(ans-ans1+mo)%mo); 65 return 0; 66 }
最后想说一下n与m的关系,假设要求0...n,m=2×n之后,n变成了大于m的2的幂次。
但是最后答案是在0...n×2中的。
像2194那个题,题面给出的信息经转化之后便可看成两个多项式相乘,对应的下标就是对应的次数。都是有道理的。
= =Manacher不会背
以上是关于[bzoj3160]万径人踪灭的主要内容,如果未能解决你的问题,请参考以下文章