【BZOJ3160】万径人踪灭 Manacher+FFT

【BZOJ3160】万径人踪灭

Description

Input

Output

Sample Input

Sample Output

HINT

题解:自己想出来1A,先撒花~(其实FFT部分挺裸的)

做这道题,第一思路很重要,显然看到这题的第一想法就是ans=总数-不合法(不要问我为什么显然)。因为向这种用补集法的题一般都会给一些很奇葩的限制条件,但是一旦换个角度去想就很水了,好了不多说废话了。

显然,不合法的情况,也就是连续的回文区间的方案数,我们直接上Manacher就搞定了嘛!答案就是所有对称轴的(最长回文串长度+1)/2之和(是的,很显然)

对于不合法的情况,我们发现两串对称的情况跟卷积的形式类似(FFT做多了吧?),但是问题来了,怎么构造出一个卷积,使得它的值就是回文子串的个数呢?

我们发现原串只有a或b,所以思考能不能构造出一种卷积,使得对应位置的值跟下面一样

a*b->0       b*a->0        a*a->1     b*b->1

如果把a看成0,b看成1,这显然是一个异或,然而并没什么卵用。但我们如果把a看成0,b看成1,可以满足只有b*b是1,其他都是0;同理,把a看成1,b看成0,可以满足只有a*a是1,其他都是0,然后我们对这两种情况分别求一次卷积,就能得到:以i为对称中心的最长子串的回文半径长度。这里注意一下,用于是两个一样的多项式相乘,所以每对字符会被算成两次(单个字符自我对称的除外),所以我们要的回文半径应该是(x+1)/2

然而半径长度并不是方案数,由于每对对称的字符都可以选或不选,所以对答案的贡献就是2^长度-1(因为你不能一个也不选吧?)

好吧,感觉说了这么多又有点说不明白了,所以欢迎提问和hack~

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#define pi acos(-1.0)
#define mod 1000000007
using namespace std;
int n,ans;
struct cp
{
	double x,y;
	cp (double a,double b){x=a,y=b;}
	cp (){}
	cp operator + (cp a){return cp(x+a.x,y+a.y);}
	cp operator - (cp a){return cp(x-a.x,y-a.y);}
	cp operator * (cp a){return cp(x*a.x-y*a.y,x*a.y+y*a.x);}
}n1[1<<20],n2[1<<20];
int s[1<<20],ret[1<<20],rl[1<<20],pn[1<<20];
char str[1<<20];
void FFT(cp *a,int len,int f)
{
	int i,j,k,h;
	cp t;
	for(i=k=0;i<len;i++)
	{
		if(i>k)	swap(a[i],a[k]);
		for(j=(len>>1);(k^=j)<j;j>>=1);
	}
	for(h=2;h<=len;h<<=1)
	{
		cp wn(cos(f*2*pi/h),sin(f*2*pi/h));
		for(j=0;j<len;j+=h)
		{
			cp w(1.0,0);
			for(k=j;k<j+h/2;k++)	t=w*a[k+h/2],a[k+h/2]=a[k]-t,a[k]=a[k]+t,w=w*wn;
		}
	}
}
void work(cp *a,cp *b,int len)
{
	FFT(a,len,1),FFT(b,len,1);
	for(int i=0;i<len;i++)	a[i]=a[i]*b[i];
	FFT(a,len,-1);
	for(int i=0;i<len;i++)	ret[i]+=(int)(a[i].x/len+0.1);
}
int main()
{
	scanf("%s",str);
	int i,mx,pos,len=strlen(str);
	for(i=0;i<len;i++)	s[n++]=0,s[n++]=str[i]-‘a‘;
	s[n++]=0;
	for(mx=-1,i=0;i<n;i++)
	{
		if(mx>i)	rl[i]=min(mx-i+1,rl[2*pos-i]);
		else	rl[i]=1;
		for(;i+rl[i]<n&&rl[i]<=i&&s[i+rl[i]]==s[i-rl[i]];rl[i]++);
		if(mx<i+rl[i]-1)	mx=i+rl[i]-1,pos=i;
	}
	for(i=0;i<n;i++)	ans=(ans-rl[i]/2+mod)%mod;
	for(len=1;len<2*n;len<<=1);
	for(i=0;i<len;i++)	n1[i]=n2[i]=cp(0,0);
	for(i=1;i<n;i+=2)	n1[i]=n2[i]=cp(s[i],0);
	work(n1,n2,len);
	for(i=0;i<len;i++)	n1[i]=n2[i]=cp(0,0);
	for(i=1;i<n;i+=2)	n1[i]=n2[i]=cp(s[i]^1,0);
	work(n1,n2,len);
	for(pn[0]=i=1;i<=n;i++)	pn[i]=(pn[i-1]<<1)%mod;
	for(i=0;i<n;i++)	ans=(ans+pn[(ret[i<<1]+(i&1))>>1]-1)%mod;
	printf("%d",ans);
	return 0;
}
时间: 2024-12-31 17:10:28

【BZOJ3160】万径人踪灭 Manacher+FFT的相关文章

BZOJ3160 万径人踪灭 【fft + manacher】

题解 此题略神QAQ orz po神牛 由题我们知道我们要求出: 回文子序列数 - 连续回文子串数 我们记为ans1和ans2 ans2可以用马拉车轻松解出,这里就不赘述了 问题是ans1 我们设\(f[i]\)表示以i位置为中心的对称的字符对数,那么i位置产生的回文子序列数 = \(2^{f[i]} - 1\) 如何求? 由对称的性质,以i为对称中心的两点\(a,b\)满足\(a+b=2*i\) 我们可以设一个这样的序列: \(c[n]\)表示以\(n/2\)位置为对称点的对称点对数[n/2若

[bzoj3160]万径人踪灭

Manacher+FFT,这题太精妙了,我现在才写是不是太弱了... Ans=以某个轴为中心的每一种回文子序列-所有连续回文串方案数 连续部分可以用Manacher在O(n)时间内解决. 第一部分:令f[i]=以i为中轴的对称对数,则对(2^f[i])-1求和即可(不能光有一根轴) 长串中i左右对称的对数位置相加一定是i(在短串中),那么f[i]=[sigma((str[x]==str[i-x])(x<i))+1]/2 这时题目还有个条件哟-串只是由a,b构成的,我们考虑一个卷积的形式C[k]=

BZOJ3160 万径人踪灭 字符串 多项式 Manachar FFT

原文链接http://www.cnblogs.com/zhouzhendong/p/8810140.html 题目传送门 - BZOJ3160 题意 给你一个只含$a,b$的字符串,让你选择一个子序列,使得: $1.$位置和字符都关于某一条对称轴对称. $2.$不能是连续的一段. 问原来的字符串中能找出多少个这样的子序列.答案对$10^9+7$取模. 串长$\leq 10^5$. 题解 下面的讨论都在满足条件$1$的情况下进行. 首先,我们先不考虑条件$2$.然后再减掉不满足条件$2$的就可以了

万径人踪灭(FFT+manacher)

传送门 这题--我觉得像我这样的菜鸡选手难以想出来-- 题目要求求出一些子序列,使得其关于某个位置是对称的,而且不能是连续一段,求这样的子序列的个数.这个直接求很困难,但是我们可以先求出所有关于某个位置对称的子序列,最后减去子串的个数. 子串个数可以用\(manacher\)求,至于子序列的话,我们假设以第\(i\)位为中心,那么如果两边有\(x\)对相同的字符,那么这个位置对答案的贡献就是\(2^x-1\)或者\(2^(x+1)-1\).(因为有可能回文串的长度是偶数,也就是不存在中间点) 考

BZOJ3160万径人踪灭

题解: 题意即求不连续但间隔长度对称的回文串个数. 若si=sj,则这对字符可以作为以(i+j)/2为中心的回文串的一部分. 用F[i]来表示可以做为以i/2为中心的回文串的一部分的字符对数,则以i/2为中心的回文串数为2^F[i]. 则这就成了多项式乘法:先做一次a的,把字符为a的位置值赋为1,其余为0,进行一次FFT:同理做一次b的. 因为完全连续是不可以的,所以用Manacher求出这样的回文串的个数并减去. 代码: (BZOJ上PASCAL跑得不够快,再加上这题时限只有10s,并没有AC

【manacher+FFT】BZOJ3160-万径人踪灭

[题目大意] 在一个仅仅含有a,b的字符串里选取一个子序列,使得: 1.位置和字符都关于某条对称轴对称: 2.不能是连续的一段. [思路] 不连续的回文串的个数=总的回文串个数-连续回文串的个数. 后者可以用manacher在O(n)时间里面求出.求的是个数不是最长串,和之前写的几道不怎么一样,注意一下. 求总的回文串个数稍微复杂一些.我们用f[i]表示以i为对称中心,两边有多少个对称的字符.对于每个中心i我们有(2^f[i])-1种方案 答案即Σ[1<=i<=n*2+1]((2^f[i])-

【BZOJ 3160】 3160: 万径人踪灭 (FFT)

3160: 万径人踪灭 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1440  Solved: 799 Description Input Output Sample Input Sample Output HINT Source 2013湖北互测week1 [分析] 看题目被吓死,其实很多废话.. 还是自己想出来了..FFT好强啊..可以加速很多东西的说. 然后就是,枚举对称轴吧? 假设a[i]==a[j],那么用i+j表示它的对称轴. 共有

bzoj 3160: 万径人踪灭 manachar + FFT

3160: 万径人踪灭 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 133  Solved: 80[Submit][Status][Discuss] Description Input Output Sample Input Sample Output HINT 以每一个位置为中心,分别处理连续一块的回文串,回文序列个数. 比较容易看出是FFT+manachar,但是FFT还是不太熟悉,特别要注意三层for语句中i,j,k不能写错,这东西很难调

BZOJ 3160 万径人踪灭 Manacher算法+快速傅里叶变换

题目大意:给定一个由'a'和'b'构成的字符串,求不连续回文子序列的个数 首先回文一定是将字符串倍增 由于求的是不连续回文子序列的个数 因此我们可以求出总回文子序列的个数,然后减掉连续的 连续的就是回文子串 用Manacher算法可以O(n)求解 不连续的就有些难搞了 首先我们令f[i]表示以i为中心的对称字符对个数 比如s[]=$#a#b#a 那么s[4]='b' f[4]=2 那么对于每个中心i我们有(2^f[i])-1种方案 答案即Σ[1<=i<=n*2+1]((2^f[i])-1) 问