• 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
    ",(ans+mod)%mod);
    	return 0;
    }
    

      


    By NeighThorn

  • 相关阅读:
    [转]用汇编实现原子操作
    贪心算法练习集
    链表练习题集
    STL测试3)优先级队列实现二叉堆
    STL测试2)计算器简单实现
    STL测试
    Java学习笔记(三)
    【JAVA】学习笔记(2)
    【Java】学习笔记(1)
    【机器学习】异常检测算法(I)
  • 原文地址:https://www.cnblogs.com/neighthorn/p/6555780.html
Copyright © 2020-2023  润新知