码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj3160 万径人踪灭

时间:2016-05-25 00:35:17      阅读:237      评论:0      收藏:0      [点我收藏+]

标签:

3160: 万径人踪灭

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 814  Solved: 459
[Submit][Status][Discuss]

Description

技术分享

技术分享

Input

技术分享

Output

Sample Input

Sample Output

HINT

技术分享

Source




吐槽:我替“千山鸟飞绝”感到不服。

manacher+FFT,思路好题

补集思想,直接求不连续的有点难,我们可以求出所有回文串,然后减去其中连续的。

连续回文串很好求,manacher就可以解决。

问题在于如何求不一定连续的回文串,如果求出每一个以每个位置i为对称中心,对称的字符对的个数f[i],那对于答案的贡献就加上2^f[i]-1,证明很显然。

于是问题又成了如何求f[i]。

发现字符串中只有两种字符,而且对称的点的下标和为定值。于是我们可以先令a=1、b=0,再令a=0、b=1,分别用FFT求出卷积,就可以得到相等且下标和为x的字符对数。




#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define maxn 300005
#define mod 1000000007
using namespace std;
int n,len,ans,rev[maxn],f[maxn],bin[maxn];
char s[maxn],st[maxn];
const double pi=acos(-1.0);
struct cp
{
	double x,y;
	cp(double xx=0,double yy=0){x=xx;y=yy;}
	friend cp operator +(cp a,cp b){return cp(a.x+b.x,a.y+b.y);}
	friend cp operator -(cp a,cp b){return cp(a.x-b.x,a.y-b.y);}
	friend cp operator *(cp a,cp b){return cp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
}a[maxn],b[maxn];
void fft(cp *x,int n,int flag)
{
	F(i,0,n-1) if (rev[i]>i) swap(x[i],x[rev[i]]);
	for(int m=2;m<=n;m<<=1)
	{
		int mid=m>>1;
		cp wn(cos(2.0*pi/m*flag),sin(2.0*pi/m*flag));
		for(int i=0;i<n;i+=m)
		{
			cp w(1.0,0);
			F(j,0,mid-1)
			{
				cp u=x[i+j],v=x[i+j+mid]*w;
				x[i+j]=u+v;x[i+j+mid]=u-v;
				w=w*wn;
			}
		}
	}
	if (flag==-1) F(i,0,n-1) x[i].x/=n;
}
void manacher()
{
	int mx=0,id=0;
	F(i,1,n)
	{
		if (mx>i) f[i]=min(mx-i,f[id*2-i]);
		else f[i]=0;
		while (s[i+f[i]]==s[i-f[i]]) f[i]++;
		if (i+f[i]>mx) mx=i+f[i],id=i;
		ans=(ans-f[i]/2+mod)%mod;
	}
}
int main()
{
	bin[0]=1;F(i,1,100000) bin[i]=bin[i-1]*2%mod;
	scanf("%s",s+1);
	len=strlen(s+1);
	n=1;int tmp=0;
	while (n<len*2) n<<=1,tmp++;
	F(i,1,n-1){rev[i]=rev[i>>1]>>1|((i&1)<<(tmp-1));}
	F(i,0,len-1) if (s[i+1]=='a') a[i].x=1;
	fft(a,n,1);
	F(i,0,n-1) a[i]=a[i]*a[i];
	fft(a,n,-1);
	F(i,0,len-1) if (s[i+1]=='b') b[i].x=1;
	fft(b,n,1);
	F(i,0,n-1) b[i]=b[i]*b[i];
	fft(b,n,-1);
	F(i,0,n-1)
	{
		int x=round(a[i].x+b[i].x);
		x=(x+1)/2;
		ans=(ans+bin[x]-1)%mod;
	}
	F(i,1,len) st[i]=s[i];
	n=len<<1|1;
	s[0]='*';s[1]='#';s[n+1]='&';
	F(i,1,len) s[i<<1]=st[i],s[i<<1|1]='#';
	manacher();
	printf("%d\n",ans);
	return 0;
}


bzoj3160 万径人踪灭

标签:

原文地址:http://blog.csdn.net/aarongzk/article/details/51494738

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!