Description
Input
Input
Sourse
2013湖北互测week1
题意大概是求不连续回文子序列的个数
ans=ans=回文子序列个数-回文子串个数
后者显然跑一边manacher的事情
前面这部分怎么处理?
我们令fifi表示倍长(加’#’)后ii这位左右对应相等的字符
那以为中心的对称子序列共有2fi−12fi−1个
问题变成了fifi怎么求
大力推一波式子
fi=∑i−1j=1[s[j]==s[2∗i−j]]fi=∑j=1i−1[s[j]==s[2∗i−j]]
这个式子已经可以FFTFFT了
为了更加直观,我们把后面的部分放到原串中
则fi=∑i−1j=1[s[j]==s[i−j]]fi=∑j=1i−1[s[j]==s[i−j]]
后面这部分我们只要分别令串中a的位置为1,b为0 和b为1,a为0直接跑FFT即可
a为1的情况跑出来就是a对fifi的贡献
#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define ll long long
#define Comp complex<double>
#ifdef M_pi
const double pi = M_pi;
#else
const double pi = acos(-1.0);
#endif
const int q = 1e9+7;
Comp t[401000];
int f[401000] , r[401000];
int mi[401000];
int p[401000];
char s[201000];
ll ans;
int n , flen , N;
void dft(Comp *a ,int f){
for(int i = 0; i < flen; ++i)
if(i < r[i]) swap(a[i], a[r[i]]);
for(int len = 2;len <= flen;len *= 2){
Comp wn = Comp( cos(2 * pi / len) , f * sin(2 * pi / len));
for(int k = 0;k <= flen / len - 1;++k){
int st = k * len;
Comp w = 1;
for(int i = 0;i < len / 2;++i){
Comp x = a[st + i],
y = a[st + i + len / 2] * w;
a[st + i] = x + y;
a[st + i + len / 2] = x - y;
w *= wn;
}
}
}
if(f == -1) rep(i,0,flen-1) a[i] = (a[i].real()/flen+0.5);
return;
}
void solve()
{
flen = 1;
while(flen < 2*(n-1)+1) flen*=2;
int l = log2(flen);
for(int i = 0;i < flen;++i){
r[i] = r[i>>1]>>1;
if(i & 1) r[i] |= 1<<(l-1);
}
rep(i,n,flen) t[i] = 0;
dft(t,1);
rep(i,0,flen-1) t[i] = t[i]*t[i];
dft(t,-1);
rep(i,0,flen-1) f[i+2] = (int)(f[i+2]+t[i].real())%q;
return;
}
void manacher()
{
int pos = 0,mx = 0;
rep(i,1,2*n)
{
p[i]=i<mx?min(p[pos*2-i],mx-i):1;
while(s[i-p[i]] == s[i+p[i]]) p[i]++;
if(i + p[i] > mx) mx = i + p[i],pos = i;
}
}
int main()
{
n++;
while(scanf("%c",&s[2*n]) != EOF && (s[2*n] == 'a'|| s[2*n] == 'b')) s[2*n-1] = '#',n++;n--;
s[2*n+1] = '!';s[0] = '?';
rep(i,0,n-1) if(s[2*i+2] == 'a') t[i] = 1;
solve();
rep(i,0,n-1) if(s[2*i+2] == 'b') t[i] = 1;
else t[i] = 0;
solve();
mi[0] = 1;
rep(i,1,n) mi[i] = (mi[i-1]<<1)%q;
rep(i,1,2*n) f[i] = (f[i]+1)/2;
rep(i,1,2*n) if(f[i] > 0)ans = (ans + mi[f[i]] - 1)%q;
manacher();
for(int i=2;i<=2*n;i+=2) if(p[i]%2==0) p[i]--;
for(int i=1;i<=2*n;i+=2) if(p[i]%2==1) p[i]--;
rep(i,1,2*n) ans = (ans-(p[i]+1)/2+q)%q;
printf("%lld\n",ans);
return 0;
}