[BZOJ3160] 万径人踪灭

[BZOJ3160] 万径人踪灭


试题分析

由于正向求是否有断开的不好求左右匹配数,那么我们换一个角度:回文串总数-连续情况
显然,连续情况manacher一下就是\(\sum_{i=1}^{2n} p_i\),其中\(2n\)是因为还有偶长度的回文串,需要添加特殊字符。
然后求总数就是\(\sum(2^{f_i}-1)\)
其中\(f_i\)为以i位置为对称轴匹配字符的个数。-1是空集情况。
这个可以直接FFT求,a,b分开计算,计算a的时候将ch[i]==a的位置赋为1,然后FFT就可以得出f。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
 
using namespace std;
#define LL long long
#define Pi 3.1415926535
const LL Mod = 1e9+7;
 
inline LL read(){
    LL x=0,f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
const LL MAXN = 4e5+5;
const LL INF = 2147483600;
 
char str2[MAXN+1],str[MAXN+1]; LL N;
LL Len[MAXN+1],f[MAXN+1];
 
LL lim=1,l,r[MAXN+1];
struct cpx{
    double a,b;
    cpx (double aa=0,double bb=0){a=aa,b=bb;}
}a[MAXN+1],b[MAXN+1];
cpx operator + (cpx a,cpx b){return cpx(a.a+b.a,a.b+b.b);}
cpx operator - (cpx a,cpx b){return cpx(a.a-b.a,a.b-b.b);}
cpx operator * (cpx a,cpx b){return cpx(a.a*b.a - a.b*b.b , a.a*b.b + a.b*b.a);}
LL M; LL rev[MAXN+1];
 
inline void FFT(cpx *A,LL type){
    for(LL i=0;i<lim;i++) if(rev[i]>i) swap(A[rev[i]],A[i]);
    for(LL mid=1;mid<lim;mid<<=1){
        cpx Wn( 1.0*cos(Pi/mid) , 1.0*type*sin(Pi/mid) );
        for(LL R=(mid<<1),j=0;j<lim;j+=R){
            cpx w(1,0);
            for(LL k=0;k<mid;k++,w=w*Wn){
                cpx x = A[j+k] , y = w*A[j+k+mid];
                A[j+k] = x + y; A[j+k+mid] = x - y;
            }
        }
    } return ;
}
inline void work(char ch){
    for(LL i=0;i<lim;i++) a[i]=cpx(str[i]==ch,0),cout<<a[i].a<<" "; cout<<endl;
    FFT(a,1); for(LL i=0;i<lim;i++) a[i]=a[i]*a[i]; FFT(a,-1);
    for(LL i=1;i<=2*N;i++) f[i]+=((LL)(a[i].a*1.0/lim+0.5)+1)/2,cout<<((LL)(a[i].a*1.0/lim+0.5)+1)/2<<" ";
    for(LL i=1;i<=2*N;i++) cout<<a[i].a<<" "; cout<<endl;
    cout<<endl;
}
LL Pw[MAXN+1];
 
int main(){
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    scanf("%s",str2+1); N=strlen(str2+1);
    LL Mx=-INF,pos=0; Pw[0]=1;
    for(LL i=1;i<=N;i++) str[i]=str2[i]; 
    for(LL i=1;i<=N;i++) Pw[i]=Pw[i-1]*2LL%Mod;
    while(lim<=2*N) lim<<=1,++l;
     
    LL ans=0; puts(str+1);
    for(LL i=0;i<lim;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
    work('a'); work('b');
    for(LL i=1;i<=2*N;i++) ans=(ans+Pw[f[i]]-1)%Mod,cout<<f[i]<<" ";
	cout<<endl; 
     
    str[0]='%'; str[2*N+1]='#'; 
    for(LL i=1;i<=N;i++) str[2*i]=str2[i],str[2*i-1]='#';
    for(LL i=1;i<=2*N;i++){
        if(Mx>i) Len[i]=min(Mx-i,Len[2*pos-i]); else Len[i]=1; 
        while(Len[i]<i&&str[i+Len[i]]==str[i-Len[i]]) ++Len[i];
        if(i+Len[i]>Mx) pos=i,Mx=i+Len[i];
    }
    for(LL i=1;i<=2*N;i++) ans=(ans-Len[i]/2+Mod)%Mod;
    printf("%lld\n",ans);
    return 0;
}
posted @ 2018-09-01 15:01  wxjor  阅读(125)  评论(0编辑  收藏  举报