【manacher+FFT】BZOJ3160-万径人踪灭
【题目大意】
在一个仅仅含有a,b的字符串里选取一个子序列,使得:
1.位置和字符都关于某条对称轴对称;
2.不能是连续的一段。
【思路】
不连续的回文串的个数=总的回文串个数-连续回文串的个数。
后者可以用manacher在O(n)时间里面求出。求的是个数不是最长串,和之前写的几道不怎么一样,注意一下。
求总的回文串个数稍微复杂一些。我们用f[i]表示以i为对称中心,两边有多少个对称的字符。对于每个中心i我们有(2^f[i])-1种方案 答案即Σ[1<=i<=n*2+1]((2^f[i])-1)。
显然f[i]=(Σ[1<=j<=i-1]bool(str[j]==str[i-j]))+1>>1。
至于如何求出f[i],我们分别用a[]、b[]记录下每一位是否出现'a'或'b'。比如ababa这样一个数组,a={10101},b={01010}
a[]的卷积就是'a'的贡献,b[]的卷积就是'b'的贡献,两者相加+1再除以2即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<complex> 6 #include<cmath> 7 #define pi acos(-1) 8 using namespace std; 9 const int MAXN=524288+50; 10 const int MOD=1000000007; 11 typedef complex<double> com; 12 typedef long long ll; 13 com a[MAXN],b[MAXN],c[MAXN]; 14 int ina[MAXN],inb[MAXN],f[MAXN],p[MAXN],Rev[MAXN],m,n,L; 15 char s[MAXN],str[MAXN]; 16 void get_bit(){for (n=1,L=0;n<m;n<<=1) L++;} 17 void get_Rev(){for (int i=0;i<n;i++) Rev[i]=(Rev[i>>1]>>1)|((i&1)<<(L-1));} 18 19 void FFT(com* a,int flag) 20 { 21 for (int i=0;i<n;i++)if(i<Rev[i])swap(a[i],a[Rev[i]]); 22 for (int i=1;i<n;i<<=1) 23 { 24 com wn(cos(pi/i),flag*sin(pi/i)); 25 for (int j=0;j<n;j+=(i<<1)) 26 { 27 com w(1,0); 28 for (int k=0;k<i;k++,w*=wn) 29 { 30 com x=a[j+k],y=w*a[j+k+i]; 31 a[j+k]=x+y; 32 a[j+k+i]=x-y; 33 } 34 } 35 } 36 if (flag==-1) for (int i=0;i<n;i++) a[i]/=n; 37 } 38 39 int manacher() 40 { 41 str[0]='$'; 42 str[1]='#'; 43 for (int i=0,j=1;s[i+1];i++) 44 { 45 str[++j]=s[i+1]; 46 str[++j]='#'; 47 } 48 int mx=0,mxid=0,ret=0; 49 memset(p,0,sizeof(p)); 50 for (int i=1;str[i];i++) 51 { 52 if (mx>i) p[i]=(p[2*mxid-i]<(mx-i)?p[2*mxid-i]:(mx-i)); 53 else p[i]=1; 54 while(str[i-p[i]]==str[i+p[i]]) p[i]++; 55 if (i+p[i]>mx) 56 { 57 mx=i+p[i]; 58 mxid=i; 59 } 60 ret=(ret+p[i]/2)%MOD; 61 } 62 //注意我们要求的不是最长回文字串而是回文串的个数,和之前的manacher有细微不同 63 return ret; 64 } 65 66 void init() 67 { 68 scanf("%s",s+1); 69 memset(ina,0,sizeof(ina)); 70 memset(inb,0,sizeof(inb)); 71 n=strlen(s+1); 72 for (int i=1;i<=n;i++) 73 if (s[i]=='a') ina[i]++; 74 else if (s[i]=='b') inb[i]++; 75 for (int i=1;i<=n;i++) a[i]=(ina[i]),b[i]=(inb[i]); 76 } 77 78 void solve() 79 { 80 m=n<<1; 81 get_bit(); 82 get_Rev(); 83 FFT(a,1); 84 FFT(b,1); 85 for (int i=0;i<n;i++) c[i]=a[i]*a[i]+b[i]*b[i]; 86 FFT(c,-1); 87 int pow[MAXN]; 88 ll ans=0; 89 pow[0]=1; 90 for (int i=1;i<MAXN;i++) pow[i]=(pow[i-1]*2)%MOD; 91 for (int i=0;i<n;i++) 92 { 93 int tmp=int(c[i].real()+0.5); 94 ans=(ans+(ll)pow[(tmp+1)>>1]-1)%MOD; 95 } 96 printf("%d",(((int)ans+MOD-manacher())%MOD)); 97 } 98 99 int main() 100 { 101 init(); 102 solve(); 103 return 0; 104 }