题意
给定一个由 a a 和构成的字符串,求不连续回文子序列的个数
题解
不连续回文子序列数=回文子序列数-回文子串数
后面的可以直接用 PAM P A M 求出来
(我才不会说因为
Manacher
M
a
n
a
c
h
e
r
能干的
PAM
P
A
M
都能干,所以弃掉了
Manacher
M
a
n
a
c
h
e
r
)
考虑回文子序列数怎么求
如果 si=sj s i = s j 那么这两个字符就关于 i+j2 i + j 2 对称
考虑 (si,sj) ( s i , s j ) 选不选就对 i+j2 i + j 2 有 ×2 × 2 的贡献
所以可以设 fi+j2= f i + j 2 = 左右两边有多少对 (si,sj) ( s i , s j ) 满足 si=sj s i = s j
去掉左右的限制 fi+j2=∑[si=sj]2 f i + j 2 = ∑ [ s i = s j ] 2
下标里面有 12 1 2 很讨嫌,而且对称中心还可能是小数
所以直接设 fi+j=∑[si=sj]2 f i + j = ∑ [ s i = s j ] 2
上面看起来是一个卷积的形式,考虑把等于变成乘法
所以就可以枚举字符集,然后用做 |c|+1 | c | + 1 遍 FFT F F T 算 fi f i
因为 FFT F F T 里如果两个字符位置相同 (si=si) ( s i = s i ) 是不会被算两遍的,所以要向上取整
然后 ⌈x2⌉=⌊x+12⌋ ⌈ x 2 ⌉ = ⌊ x + 1 2 ⌋
然后全集 Sum=∑2ni=12fi−1 S u m = ∑ i = 1 2 n 2 f i − 1 (非空子集)
#include<bits/stdc++.h>
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define go(u) for(register int i=fi[u],v=e[i].to;i;v=e[i=e[i].nx].to)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=1e5+5,M=1<<18,P=1e9+7;
inline int pls(int a,int b){return a+=b,a>=P?a-P:a;}
inline int sub(int a,int b){return a-=b,a<0?a+P:a;}
struct PAM{
int n,T,las;char s[N];
struct node{int fail,len,cnt,ch[26];}a[N];
inline void init(){las=n=0;T=a[0].fail=1;s[0]=a[1].len=-1;}
inline int gf(int x){while(s[n-a[x].len-1]^s[n])x=a[x].fail;return x;}
inline void ins(int v){
s[++n]=v;las=gf(las);
if(!a[las].ch[v]){
a[++T]={a[gf(a[las].fail)].ch[v],a[las].len+2};
a[las].ch[v]=T;
}++a[las=a[las].ch[v]].cnt;
}
inline int calc(){
int tp=0;
fd(i,T,2)a[a[i].fail].cnt=pls(a[a[i].fail].cnt,a[i].cnt),tp=pls(tp,a[i].cnt);
return tp;
}
}p;
int n,K,ans,pw[M],R[M];char s[N];
struct cp{
double x,y;
inline cp operator+(const cp&b){return(cp){x+b.x,y+b.y};}
inline cp operator-(const cp&b){return(cp){x-b.x,y-b.y};}
inline cp operator*(const cp&b){return(cp){x*b.x-y*b.y,x*b.y+y*b.x};}
}a[M],b[M],w[M];
const double pi=acos(-1),eps=0.1;
inline void fft(cp*const a,const int tp){
fp(i,0,K-1)if(i>R[i])swap(a[i],a[R[i]]);
for(int i=2;i<=K;i<<=1){
int d=i>>1;cp e=cp{cos(pi/d),tp*sin(pi/d)},o;
for(int j=d;j>=0;j-=2)w[j]=w[j>>1];
for(int j=1;j<=d;j+=2)w[j]=w[j-1]*e;
for(cp*x=a;x!=a+K;x+=i)fp(k,0,d-1)
o=x[k+d]*w[k],x[k+d]=x[k]-o,x[k]=x[k]+o;
}
}
int main(){
#ifndef ONLINE_JUDGE
file("s");
#endif
scanf("%s",s);n=strlen(s);p.init();
w[0]={1};K=1;while(K<n<<1)K<<=1;pw[0]=1;
fp(i,1,K-1)pw[i]=pls(pw[i-1],pw[i-1]);
fp(i,0,n-1)s[i]=='a'?a[i].x=1:b[i].x=1;
for(int i=0,j=0;i<K;++i){R[i]=j;for(int l=K>>1;(j^=l)<l;l>>=1);}
fft(a,1),fft(b,1);fp(i,0,K-1)a[i]=a[i]*a[i]+b[i]*b[i];fft(a,-1);
fp(i,0,K-1)ans=pls(ans,pw[(int(a[i].x/K+eps)+1)>>1]-1);
fp(i,0,n-1)p.ins(s[i]-'a');
printf("%d",sub(ans,p.calc()));
return 0;
}