BZOJ 3160: 万径人踪灭

3160: 万径人踪灭

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 1263  Solved: 701
[Submit][Status][Discuss]

Description

Input

Output

 

Sample Input

 

Sample Output

 

HINT

 

 

Source

分析:

求所有不连续回文子序列的个数,我们先去掉不连续这个条件,求出所有回文子序列的个数,然后减去回文子串的个数就是答案...

考虑怎么求回文子序列的个数,发现回文子序列是由若干个以同一位置为对称轴的对称字符对组成,所以我们计算出$g[i]$代表以$i$为对称轴的对称字符对的个数$(i$代表的是倍增之后的字符串...$)$,然后$2^{g[i]}-1$就是$f[i]$...

那么观察发现,每一对对称字符对的下标加起来是对称轴在倍增之后的字符串中的下标...诶,这就很好办了...$FFT$一发就计算出了答案...

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<complex>
#include<cstdio>
//by NeighThorn
#define pi acos(-1)
using namespace std;

const int maxn=500000+5,mod=1e9+7;
typedef complex<double> M;

int n,m,L,ans,len,R[maxn],p[maxn];

M a[maxn],f[maxn],g[maxn];

char s[maxn],str[maxn];

inline int power(int x,int y){
	int res=1;
	while(y){
		if(y&1)
			res=1LL*res*x%mod;
		x=1LL*x*x%mod,y>>=1;
	}
	return res;
}

inline void FFT(M *a,int f){
    for(int i=0;i<n;i++)
        if(i>R[i]) swap(a[i],a[R[i]]);
    for(int i=1;i<n;i<<=1){
        M wn(cos(pi/i),f*sin(pi/i));
        for(int j=0;j<n;j+=(i<<1)){
            M w(1,0);
            for(int k=0;k<i;k++,w*=wn){
                M x=a[j+k],y=w*a[j+k+i];
                a[j+k]=x+y,a[j+k+i]=x-y;
            }
        }
    }
    if(f==-1)
        for(int i=0;i<n;i++)
            a[i]/=n;
}

inline void prework(void){
	str[0]='$';int i;
	for(i=0;s[i];i++)
		str[2*i+1]='#',str[2*(i+1)]=s[i];
	len=2*i+1,str[len]=str[len+1]='#';
}

inline void manacher(void){
	int id,mx=0;
	for(int i=1;i<len;i++){
		p[i]=i<mx?min(p[id*2-i],mx-i):1;
		while(str[i-p[i]]==str[i+p[i]])
			p[i]++;
		if(p[i]+i>mx)
			id=i,mx=p[i]+i;
	}
	for(int i=1;i<len;i++)
		ans=((ans-p[i]/2)%mod+mod)%mod;
}

signed main(void){
#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
#endif
	scanf("%s",s);prework();m=len;
	for(n=1;n<=m;n<<=1) L++;
	for(int i=0;i<n;i++)
		R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
	manacher();
	for(int i=0;s[i];i++)
		if(s[i]=='a') a[i]=1;
	FFT(a,1);
	for(int i=0;i<n;i++) f[i]=a[i]*a[i],a[i]=0;
	FFT(f,-1);
	for(int i=0;s[i];i++)
		if(s[i]=='b') a[i]=1;
	FFT(a,1);
	for(int i=0;i<n;i++) g[i]=a[i]*a[i];
	FFT(g,-1);
	for(int i=0,x;i<n;i++)
		x=f[i].real()+g[i].real()+0.1,x=(x+1)>>1,ans=(ans+power(2,x)-1)%mod;
	printf("%d\n",(ans+mod)%mod);
	return 0;
}

  


By NeighThorn

 

posted @ 2017-03-15 18:49  NeighThorn  阅读(241)  评论(0编辑  收藏  举报