传送门
题目大意:在一个只含ab的字符串中选取一个子序列,使得:1、字符和下标都关于一个中心对称2、不能是连续的一段。求方案数。
这题我的方法好蠢啊→_→
首先容斥一下,答案=所有子序列的方案数-回文子串的数量
由于回文的连续子序列一定满足下标对称,所以可以直接用manacher求出回文子串的数量
然后就是统计所有子序列的方案数的问题了
将a和b分开考虑,f(i)和g(i)表示当前这一位是否是当前这个字符,非1即0。然后还是像manacher一样在两个字符串中插入分割符的话,对于一个回文中心i,令F(2i)表示回文中心为i的最长回文子序列长度,那么 F(2i)=∑jf(j)g(2i−j) ,是一个卷积的形式,可以两遍FFT求出然后求和
求出以每一个点为回文中心的最长回文子序列长度了之后F(2i),就是计算方案数的问题,容易知道每一个回文中心的贡献是 2F(2i)−1
但是这个方法确实蠢极了!!实际上,满足回文的子序列一定满足对应的元素下标之和为一个定值,无论长度为奇数还是偶数!所以直接一个最简单的式子 F(i)=∑jf(i−j)g(j) 就可以解决了。。这里的F(i)的含义应该是对应元素下标之和为i的回文子序列最长长度
#include
#include
#include
#include
#include
using namespace std;
#define N 1000005
#define Mod 1000000007
const double pi=acos(-1.0);
int lss,ls,p[N],mi[N],F[N],n,m,L,R[N],ans;
char s[N],ss[N];
struct complex
{
double x,y;
complex(double X=0,double Y=0)
{
x=X,y=Y;
}
}a[N],b[N];
complex operator + (complex a,complex b) {return complex(a.x+b.x,a.y+b.y);}
complex operator - (complex a,complex b) {return complex(a.x-b.x,a.y-b.y);}
complex operator * (complex a,complex b) {return complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
int manacher()
{
int id=0,mx=0;
for (int i=1;iif (mx>i) p[i]=min(p[2*id-i],mx-i);
else p[i]=1;
while (s[i-p[i]]==s[i+p[i]]) ++p[i];
if (i+p[i]>mx)
{
mx=i+p[i];
id=i;
}
}
int ans=0;
for (int i=1;i<=ls;++i)
{
if (p[i]==1) continue;
ans+=(p[i]-2)/2+1;
ans%=Mod;
}
return ans;
}
void FFT(complex a[N],int opt)
{
for (int i=0;iif (ifor (int k=1;k1)
{
complex wn=complex(cos(pi/k),opt*sin(pi/k));
for (int i=0;i1))
{
complex w=complex(1,0);
for (int j=0;jcomplex x=a[i+j],y=w*a[i+j+k];
a[i+j]=x+y,a[i+j+k]=x-y;
}
}
}
}
void calc()
{
FFT(a,1);FFT(b,1);
for (int i=0;i<=n;++i) a[i]=a[i]*b[i];
FFT(a,-1);
for (int i=0;i<=n;++i)
F[i]+=(int)(a[i].x/n+0.5);
}
int main()
{
scanf("%s",ss);lss=strlen(ss);s[ls++]='*';
for (int i=0;i'#',s[ls++]=ss[i];
s[ls++]='#';
ans-=manacher();
m=ls+ls-2;
for (n=1;n<=m;n<<=1) ++L;
for (int i=0;i>1]>>1)|((i&1)<<(L-1));
for (int i=0;i<=n;++i) a[i]=complex(0,0),b[i]=complex(0,0);
for (int i=0;i'a')?1:0;
calc();
for (int i=0;i<=n;++i) a[i]=complex(0,0),b[i]=complex(0,0);
for (int i=0;i'b')?1:0;
calc();
mi[0]=1;for (int i=1;i<=ls;++i) mi[i]=(mi[i-1]<<1)%Mod;
for (int i=0;iint cnt=F[i<<1];
if (!cnt) continue;
ans+=mi[(cnt-1)/2+1]-1;ans%=Mod;
}
ans=(ans+Mod)%Mod;
printf("%d\n",ans);
}