BZOJ 3160 万径人踪灭 (FFT+manacher)
题目要求我们求一个序列的回文子序列数量
可以用$FFT$搞定
对于每种字符单独处理,以小写字母$a$为例
把$a$所在的所有位置设为$1$,反之设为$0$
卷积一下,会发现位置i卷出来的积就可能作为以$i/2$为中心的回文子序列的一个位置,设这个值为$x$
那么以$i/2$为中心的回文子序列数量就是$2^x$
然后题目还要求这种回文子序列不能是连续的,即不能是回文串
用$manacher$去掉这部分不合法答案即可
细节比较多
1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define N1 (1<<18)+10 6 #define M1 40010 7 #define ll long long 8 #define dd double 9 #define inf 0x3f3f3f3f 10 using namespace std; 11 12 int gint() 13 { 14 int ret=0,fh=1;char c=getchar(); 15 while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();} 16 while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();} 17 return ret*fh; 18 } 19 const dd pi=acos(-1); 20 const ll mod=1000000007; 21 ll qpow(ll x,ll y) 22 { 23 ll ans=1; 24 for(;y;x=x*x%mod,y>>=1) 25 if(y&1) ans=ans*x%mod; 26 return ans; 27 } 28 struct cp{ 29 dd x,y; 30 friend cp operator + (const cp &s1,const cp &s2){ return (cp){s1.x+s2.x,s1.y+s2.y}; } 31 friend cp operator - (const cp &s1,const cp &s2){ return (cp){s1.x-s2.x,s1.y-s2.y}; } 32 friend cp operator * (const cp &s1,const cp &s2){ return (cp){s1.x*s2.x-s1.y*s2.y,s1.y*s2.x+s1.x*s2.y}; } 33 }A[N1],B[N1],C[N1]; 34 35 void init() 36 { 37 memset(A,0,sizeof(A)); 38 memset(B,0,sizeof(B)); 39 memset(C,0,sizeof(C)); 40 } 41 42 int r[N1]; 43 void FFT(cp *s,int len,int type) 44 { 45 int i,j,k; 46 for(i=0;i<len;i++) if(i<r[i]) swap(s[i],s[r[i]]); 47 for(k=2;k<=len;k<<=1) 48 { 49 cp wn=(cp){cos(2.0*pi*type/k),sin(2.0*pi*type/k)},w,t; 50 for(i=0;i<len;i+=k) 51 { 52 w=(cp){1,0}; 53 for(j=0;j<(k>>1);j++,w=w*wn) 54 { 55 t=w*s[i+j+(k>>1)]; 56 s[i+j+(k>>1)]=s[i+j]-t; 57 s[i+j]=s[i+j]+t; 58 } 59 } 60 } 61 } 62 void FFT_Main(int len) 63 { 64 FFT(A,len,1); FFT(B,len,1); 65 for(int i=0;i<len;i++) C[i]=A[i]*B[i]; 66 FFT(C,len,-1); 67 for(int i=0;i<len;i++) C[i].x/=len; 68 } 69 70 int n,m,len,L,f[N1]; 71 char str[N1],sstr[N1]; 72 ll ans[N1]; 73 74 75 int main() 76 { 77 scanf("%s",str); n=strlen(str); 78 int i,mr,mid; ll ret=0,tmp=0; 79 for(len=1,L=0;len<n+n;len<<=1,L++); 80 for(i=0;i<len;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1)); 81 82 for(i=0;i<n;i++) A[i].x=(str[i]=='a'),B[i].x=(str[i]=='a'); 83 FFT_Main(len); 84 for(i=0;i<n;i++) ans[i+2]+=((int)(C[i].x+0.1))/2; 85 86 init(); 87 for(i=0;i<n;i++) A[i].x=(str[i]=='b'),B[i].x=(str[i]=='b'); 88 FFT_Main(len); 89 for(i=0;i<n;i++) ans[i+2]+=((int)(C[i].x+0.1))/2; 90 91 init(); 92 for(i=0;i<n;i++) A[i].x=(str[n-i-1]=='a'),B[i].x=(str[n-i-1]=='a'); 93 FFT_Main(len); 94 for(i=0;i<n;i++) ans[2*n-i]+=((int)(C[i].x+0.1))/2; 95 96 init(); 97 for(i=0;i<n;i++) A[i].x=(str[n-i-1]=='b'),B[i].x=(str[n-i-1]=='b'); 98 FFT_Main(len); 99 for(i=0;i<n;i++) ans[2*n-i]+=((int)(C[i].x+0.1))/2; 100 101 ans[n+1]/=2; 102 mr=2,mid=1,f[1]=1; 103 for(i=0,sstr[0]='$',sstr[1]='#';i<n;i++) 104 sstr[(i+1)<<1]=str[i],sstr[(i+1)<<1|1]='#'; 105 for(i=2;i<=2*n+1;i++) 106 { 107 if(i<mr) f[i]=min(f[2*mid-i],mr-i); 108 else f[i]=1; 109 while(sstr[i-f[i]]==sstr[i+f[i]]) f[i]++; 110 if(i+f[i]>mr) 111 mr=i+f[i],mid=i; 112 } 113 for(i=1;i<=2*n+1;i++) 114 ret=(ret+qpow(2,ans[i]+(!(i&1)))-1-(f[i]-(i&1))/2+mod)%mod; 115 printf("%lld\n",ret); 116 return 0; 117 }