恩,VFK大大出的题,很有(du)趣(liu)的说
题目大意:
就是给你一个只含ab的字符串,计算不连续的回文子序列的个数
我们可以先求出回文子序列的个数,再减去回文子串的个数,其中后者可以用马拉车在
O(n)
时间内解决,现在的问题就是计算回文子序列的个数
我们以abaabaa为例
我们先将其写为
a0
#
b1
#
a2
#
a3
#
b4
#
a5
#
a6
我们考虑以第
i
个字符(或#)为中心时的情况,我们只要算出关于
可以发现,关于
比如说对
形式化的,我们记
细节可以参考代码(玛雅,我又把模数打错调了一晚上…):
#include <bits/stdc++.h>
using namespace std;
typedef complex<double> Comp;
const int MAXN=int(1e5+5),MOD=int(1e9+7),_=1<<18;
const Comp I(0,1);
const double PI=acos(-1);
int bin[MAXN]={1};
char s[MAXN],q[MAXN<<1];
int p[MAXN<<1];
int Manacher(){
int len=strlen(s);
q[0]='$';q[1]='#';
for(int i=0;i<len;i++) q[(i+1)<<1]=s[i],q[(i+1)<<1|1]='#';
int n=(len+1)<<1; q[n]=0;
int mx=1,id=1,ans=0;
for(int i=1;i<n;i++){
p[i]=mx>i?min(mx-i,p[(id<<1)-i]):1;
while(q[i-p[i]]==q[i+p[i]]) p[i]++;
if(p[i]+i>mx) mx=p[i]+i,id=i;
(ans+=(p[i]>>1))%=MOD;
}
return ans;
}
Comp A[_],B[_],t[_];
void DFT(int n,Comp *A,int d){
if(n==1) return;
int n_2=n>>1;
for(int i=0;i<n_2;i++)
t[i]=A[i<<1],t[i+n_2]=A[i<<1|1];
memcpy(A,t,n<<4);
Comp *A0=A,*A1=A+n_2;
DFT(n_2,A0,d); DFT(n_2,A1,d);
Comp root=exp(I*(2.0*PI/n*d)),w(1);
for(int i=0;i<n_2;i++,w*=root)
t[i]=A0[i]+w*A1[i],t[i+n_2]=A0[i]-w*A1[i];
memcpy(A,t,n<<4);
}
int main(){
scanf("%s",s);
int ans=-Manacher(),n,len=strlen(s);
for(n=1;n<(len<<1)-1;n<<=1);
for(int i=1;i<=(len>>1)+1;i++) bin[i]=(bin[i-1]<<1)%MOD;
for(int i=0;i<len;i++) A[i]=s[i]=='a';
DFT(n,A,1);
for(int i=0;i<n;i++) B[i]=A[i]*A[i];
memset(A,0,n<<4);
for(int i=0;i<len;i++) A[i]=s[i]=='b';
DFT(n,A,1);
for(int i=0;i<n;i++) B[i]+=A[i]*A[i];
DFT(n,B,-1);
for(int i=0;i<n;i++) B[i]/=n;
for(int i=0;i<n;i++)
(ans+=bin[(int(B[i].real()+1.5))>>1]-1)%=MOD;
printf("%d\n",(ans+MOD)%MOD);
return 0;
}