zoukankan      html  css  js  c++  java
  • bzoj3160 万径人踪灭

    题目大意:给你一个ab序列,问不连续回文子序列的个数.

    FFT加上一些计数原理即可A掉此题,主要需要注意的是两字符间的位置也需要运算.

    对FFT,感觉就是一个双重循环,不过这个双重循环内部运算必须是乘法,而且复杂度不错.

    无聊的话,每个FFT的题基本上都可以写成双重循环的结构.

    顺便学一下mancher.

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<ctime>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<set>
    #include<map>
    #include<iomanip>
    using namespace std;
    #define LL long long
    #define up(i,j,n) for(LL i=j;i<=n;i++)
    #define pii pair<LL,LL>
    #define db double
    #define eps 1e-4
    #define FILE "dealing"
    LL read(){
    	LL x=0,f=1,ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0',ch=getchar();}
    	return x*f;
    }
    const LL maxn=401000,inf=1000000000000000LL,limit=20000,mod=1000000007;
    bool cmin(LL& a,LL b){return a>b?a=b,true:false;}
    bool cmax(LL& a,LL b){return a<b?a=b,true:false;}
    namespace Mancher{
    	char ch[maxn];
    	LL p[maxn];
    	LL solve(char* s,LL n){
    		LL mx=0,id=0,m=0;
    		ch[m++]='&';ch[m++]='#';
    		up(i,0,n-1){
    			ch[m++]=s[i];
    			ch[m++]='#';
    		}
    		for(LL i=1;i<m;i++){
    			if(i<mx)p[i]=min(p[2*id-i],mx-i);
    			else p[i]=1;
    			while(ch[i+p[i]]==ch[i-p[i]])p[i]++;
    			if(i+p[i]>mx){
    				mx=i+p[i];
    				id=i;
    			}
    		}
    		LL ret=0;
    		for(LL i=1;i<m;i++)ret=(ret+p[i]/2)%mod;
    		return ret;
    	}
    };
    namespace FFT{
    	struct cp{
    		db x,y;
    		cp(db x=0,db y=0):x(x),y(y){}
    		cp operator+(const cp& b){return cp(x+b.x,y+b.y);}
    		cp operator-(const cp& b){return cp(x-b.x,y-b.y);}
    		cp operator*(const cp& b){return cp(x*b.x-y*b.y,x*b.y+y*b.x);}
    	}w[maxn],A[maxn],B[maxn];
    	inline void swap(cp& a,cp& b){cp t(a);a=b;b=t;}
    	LL R[maxn],H=1,L=1;
    	db pi=(acos(-1.0));
    	void FFT(cp* a,LL f){
    		for(LL i=0;i<L;i++)if(i<R[i])swap(a[i],a[R[i]]);
    		for(LL len=2;len<=L;len<<=1){
    			LL l=len>>1;
    			cp wn(cos(pi/l),f*sin(pi/l));
    			for(LL i=1;i<l;i++)w[i]=w[i-1]*wn;
    			for(LL st=0;st<L;st+=len){
    				for(LL k=0;k<l;k++)	{
    					cp x=a[st+k],y=w[k]*a[st+k+l];
    					a[st+k]=x+y,a[st+k+l]=x-y;
    				}
    			}
    		}
    		if(f==-1)up(i,0,L-1)a[i].x/=L;
    	}
    	void solve(LL* c,LL* d,LL n,LL m,LL* ch){
    		for(H=0,L=1;L<n+m-1;H++)L<<=1;
    		up(i,0,L-1)A[i].x=c[i],A[i].y=0;
    		up(i,0,L-1)B[i].x=d[i],B[i].y=0;
    		w[0].x=1;
    		up(i,0,L)R[i]=(R[i>>1]>>1)|((i&1)<<(H-1));
    		FFT(A,1);FFT(B,1);
    		for(LL i=0;i<L;i++)A[i]=A[i]*B[i];
    		FFT(A,-1);
    		for(LL i=0;i<L;i++)ch[i]=(LL)(A[i].x+0.5);
    	}
    };
    LL n;
    char s[maxn],ch[maxn];
    LL a[maxn],b[maxn],c[maxn];
    LL mul(LL a,LL b){LL ans=1;for(;b;a=a*a%mod,b>>=1)if(b&1)ans=ans*a%mod;return ans;}
    LL f[maxn];
    int main(){
    	freopen(FILE".in","r",stdin);
    	freopen(FILE".out","w",stdout);
    	scanf("%s",s);
    	n=strlen(s);
    	up(i,0,n-1)ch[i]=s[i];
    	LL y=Mancher::solve(ch,n);
    	up(i,0,n-1)a[i]=s[i]=='a';
    	up(i,0,n-1)b[i]=s[i]=='b';
    	FFT::solve(a,a,n,n,c);
    	for(int i=0;i<n<<1;i++)f[i]+=c[i];
    	FFT::solve(b,b,n,n,c);
    	for(int i=0;i<n<<1;i++)f[i]+=c[i];
    	LL ans=0;
    	for(int i=0;i<n<<1;i++)
    		ans=(ans+mul(2,(f[i]+1)/2)+mod-1)%mod;
    	ans=(ans%mod-y+mod)%mod;
    	printf("%lld
    ",ans);
    	return 0;
    }
    

      

  • 相关阅读:
    令我印象最深刻的三个老师
    硬盘大于2T安装CentOS7.X时要注意分区
    Linux网卡配置
    Python13:文件操作
    Python12:集合
    Python11:字典
    Python10:String字符串
    Python09:元组
    Python08:列表
    Python07:模块初识
  • 原文地址:https://www.cnblogs.com/chadinblog/p/6501239.html
Copyright © 2011-2022 走看看